Adam Dohojda, Kacper Kiereś, Dawid Koceniak, Wiktoria Stęczna
Praca przedstawia próbę analizy i klasyfikacji obserwacji z wybranego repozytorium Machine Learningu dostępne tutaj. Proces przetwarzania danych zawiera wstępną analizę danych w postaci obliczenia statystyk opisowych, standaryzacji zmiennych oraz wykorzystanie modeli klasyfikacyjnych (regresji liniowej, SVM, KNN, sieci neuronowych, lasów losowych, drzew decyzyjnych, LDA, QDA) by przyporządkować obseracje do konkretnej kategorii. Na koniec robimy podsumowanie naszych wyników w postaci zestawienia tabelarycznego poszczególnych wskaźników określających dokładność dopasowania kategorii naszych obserwacji.
Przedmiotem badania są dwie odmiany ryżu uprawianych w Turcji - Osmanick oraz Cammeo. Każdy z tych gatunków wyróżnia się swoimi właściwościami. Wykonano 3810 zdjęć ziaren ryżu obu gatunków, przetworzono je i dokonano wnioskowania o cechach. Uzyskano 8 cech morfologicznych, które zapisano w repozytorium.
Mając do dyspozycji dane dotyczące dwóch gatunków ryżu, chcieliśmy dokonać klasyfikacji, które należą do gatunku $Cammeo$, a które do $Osmancik$.
area - liczba pikseli na granicach ziarna ryżu
perimeter - obwód, obliczony na podstawie między pikselami wokół granic ziarna ryżu
Major_Axis_Length - najdłuższa linia, jaką można narysować na ziarnie ryżu, tj. odległość osi głównej
Minor_Axis_Length - najkrótsza linia, jaką można narysować na ziarnie ryżu, tj. odległość osi głównej
Eccentricity - mierzy on, jak okrągła jest elipsa, która ma te same momenty co ziarno ryżu
Convex_area - zwraca liczbę pikseli najmniejszej wypukłej powłoki obszaru utworzonego przez ziarno ryżu
Extent - Zwraca stosunek obszaru utworzonego przez ziarno ryżu do obwiedni
Class - Cammeo oraz Osmancik
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.decomposition import PCA
import pandas as pd
import numpy as np
import random
import matplotlib.pyplot as plt
from sklearn.metrics import accuracy_score
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA
from sklearn.svm import SVC
from sklearn.linear_model import Perceptron
from sklearn.preprocessing import LabelEncoder
from matplotlib.colors import ListedColormap
from sklearn.model_selection import StratifiedKFold
from sklearn.pipeline import make_pipeline
from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import cross_val_score
import seaborn as sns
from scipy.stats import skew, kurtosis
from sklearn.metrics import confusion_matrix
from sklearn.metrics import roc_curve, auc
from numpy import interp
from sklearn.metrics import precision_score
from sklearn.metrics import recall_score, f1_score
from sklearn.metrics import matthews_corrcoef
from sklearn.metrics import make_scorer
from sklearn.tree import DecisionTreeClassifier
from scipy.stats import randint
from sklearn.neural_network import MLPClassifier
from sklearn.pipeline import Pipeline
from sklearn.model_selection import validation_curve
from sklearn.model_selection import learning_curve
from sklearn.model_selection import RandomizedSearchCV
from sklearn.neighbors import KNeighborsClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.discriminant_analysis import QuadraticDiscriminantAnalysis as QDA
df = pd.read_excel('rice.xlsx').set_index('Class')
np.sum(np.isnan(df), axis=0)
Area 0 Perimeter 0 Major_Axis_Length 0 Minor_Axis_Length 0 Eccentricity 0 Convex_Area 0 Extent 0 dtype: int64
Stwierdzamy brak pustych wartości
W tym kroku zwizualizujemy wszystkie zmienne, chcąc otrzymać histogramy gęstości (tak więc oś pionowa przedstawia częstości, zamiast liczby występujących wartości zmiennej). Dodatkowo w celu pogłębionego zrozumienia skorzystaliśmy z metody kdeplot z pakietu SeaBorn w celu nakreślenia estymowanej krzywej gęstości. Więcej o zaimplementowanej metodzie można poczytać tutaj.
plt.style.use('fast')
fig, axs = plt.subplots(nrows=4, ncols=2, figsize=(12,10))
plt.subplots_adjust(hspace=0.5)
for ax, col in zip(axs.flat, df.columns):
ax.hist(df[col], bins=10, density=True)
sns.kdeplot(df[col], ax=ax)
ax.grid(True)
ax.set_title(col)
ax.set_xlabel('')
skewnesses = skew(df, axis=0)
kurtosises = kurtosis(df, axis=0)
stats = pd.concat([df.describe(), pd.DataFrame({'skewness':skewnesses, 'kurtosis':kurtosises}, index=df.columns).T]).T
stats['coef_of_var'] = stats['std'] / stats['mean']
stats
| count | mean | std | min | 25% | 50% | 75% | max | skewness | kurtosis | coef_of_var | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| Area | 3810.0 | 12667.727559 | 1732.367706 | 7551.000000 | 11370.500000 | 12421.500000 | 13950.000000 | 18913.000000 | 0.325030 | -0.432091 | 0.136754 |
| Perimeter | 3810.0 | 454.239180 | 35.597081 | 359.100006 | 426.144752 | 448.852493 | 483.683746 | 548.445984 | 0.221275 | -0.840715 | 0.078366 |
| Major_Axis_Length | 3810.0 | 188.776222 | 17.448679 | 145.264465 | 174.353855 | 185.810059 | 203.550438 | 239.010498 | 0.260140 | -0.952128 | 0.092430 |
| Minor_Axis_Length | 3810.0 | 86.313750 | 5.729817 | 59.532406 | 82.731695 | 86.434647 | 90.143677 | 107.542450 | -0.134844 | 0.559801 | 0.066384 |
| Eccentricity | 3810.0 | 0.886871 | 0.020818 | 0.777233 | 0.872402 | 0.889050 | 0.902588 | 0.948007 | -0.449072 | 0.069405 | 0.023473 |
| Convex_Area | 3810.0 | 12952.496850 | 1776.972042 | 7723.000000 | 11626.250000 | 12706.500000 | 14284.000000 | 19099.000000 | 0.319656 | -0.466788 | 0.137191 |
| Extent | 3810.0 | 0.661934 | 0.077239 | 0.497413 | 0.598862 | 0.645361 | 0.726562 | 0.861050 | 0.343684 | -1.030324 | 0.116687 |
df = pd.read_excel('rice.xlsx', header=None)
X = df.loc[1:, :6].values
y = df.loc[1:, 7].values
Używając obiektu LabelEncoder, przekształcamy etykiety klas na liczby całkowite
le = LabelEncoder()
y = le.fit_transform(y)
print("Class labels: ", le.classes_)
Class labels: ['Cammeo' 'Osmancik']
le.transform(['Cammeo', 'Osmancik'])
array([0, 1])
X_train, X_test, y_train, y_test = \
train_test_split(X, y, test_size = 0.2,
stratify = y,
random_state = 0)
print('Labels counts in y: ', np.bincount(y))
print('Labels counts in y_train: ', np.bincount(y_train))
print('Labels counts in y_test: ', np.bincount(y_test))
Labels counts in y: [1630 2180] Labels counts in y_train: [1304 1744] Labels counts in y_test: [326 436]
sc = StandardScaler()
sc.fit(X_train)
X_train_std = sc.fit_transform(X_train)
X_test_std = sc.transform(X_test)
Implementacja funkcji do wizualizacji granic decyzyjnych dwuwymiarowych danych
def plot_decision_regions(X, y, classifier, test_idx=None, resolution=0.02):
# Setup marker generator and color map
markers = ('o', 's', '^', 'v', '<', '>', 'D', 'P', 'X', '*')
colors = ('red', 'blue', 'lightgreen', 'gray', 'cyan', 'orange', 'purple', 'pink', 'yellow', 'black')
cmap = ListedColormap(colors[:len(np.unique(y))])
# Plot the decision surface
x1_min, x1_max = X[:, 0].min() - 1, X[:, 0].max() + 1
x2_min, x2_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx1, xx2 = np.meshgrid(np.arange(x1_min, x1_max, resolution),
np.arange(x2_min, x2_max, resolution))
lab = classifier.predict(np.array([xx1.ravel(), xx2.ravel()]).T)
lab = lab.reshape(xx1.shape)
plt.contourf(xx1, xx2, lab, alpha=0.3, cmap=cmap)
plt.xlim(xx1.min(), xx1.max())
plt.ylim(xx2.min(), xx2.max())
# Plot class examples
for idx, cl in enumerate(np.unique(y)):
plt.scatter(x=X[y == cl, 0],
y=X[y == cl, 1],
alpha=0.8,
c=colors[idx],
marker=markers[idx],
label=f'Class {cl}',
edgecolor='black')
Funkcja rysuje obszar decyzyjny na podstawie danych treningowych i klasyfikatora, a także wyświetla przykłady klas.
Definiujemy liczbę kolorów i znaczników oraz tworzymy mapę kolorów z listy kolorów za pomocą ListedColormap.
Tworzymy siatkę punktów xx1 i xx2 na podstawie minimalnych i maksymalnych wartości cech, a następnie przewidujemy klasy dla każdego punktu na siatce za pomocą modelu klasyfikatora classifier.predict. Wynikowy konturowy wykres przedstawia obszar decyzyjny, gdzie różne kolory odpowiadają różnym klasom, a punkty treningowe są również wyświetlane na wykresie, reprezentując różne klasy.
Dodatkowo, używając różnych markerów markers i kolorów colors, funkcja oznacza punkty dla różnych klas na wykresie, co pozwala wizualnie rozróżnić klasy.
plot_decision_regions będzie przez nas wykorzystywany, kiedy wyłonimy w dalszej części projektu modele, o jak najlepszej dokładności dopasowania do danych.
Inicjalizacja tranformatora PCA i estymatora regresji logistycznej
pca = PCA(n_components = 2)
lr = LogisticRegression(multi_class = 'ovr',
random_state = 1,
solver = 'lbfgs')
Redukcja wymiarów
X_train_pca = pca.fit_transform(X_train_std)
X_test_pca = pca.transform(X_test_std)
Dopasowywanie modelu regresji logistycznej do zredukowanego zbioru danych
lr.fit(X_train_pca, y_train)
plot_decision_regions(X_train_pca, y_train, classifier = lr)
plt.xlabel('PC 1')
plt.ylabel('PC 2')
plt.legend(loc = 'best')
plt.tight_layout()
plt.show()
plot_decision_regions(X_test_pca, y_test, classifier = lr)
plt.xlabel('PC 1')
plt.ylabel('PC 2')
plt.legend(loc = 'best')
plt.tight_layout()
plt.show()
Normalizujemy kolumny w zbiorze danych za pomocą StandardScaler, kompresujemy dane do dwuwymiarowej podprzestrzeni za pomocą PCA. a następnie przekazujemy je do klasyfikatora regresji logistycznej LogisticRegression, za pomocą funkcji make_pipeline.
pipe_lr = make_pipeline(StandardScaler(),
PCA(n_components = 2),
LogisticRegression())
pipe_lr.fit(X_train, y_train)
y_pred = pipe_lr.predict(X_test)
test_acc_lr = pipe_lr.score(X_test, y_test)
print(f'Test accuracy: {test_acc_lr: .3f}')
Test accuracy: 0.923
Funkcja make_pipeline pobiera dowolną liczbę transformatorów scikit-learn, a następnie estymator scikit-learn, który implementuje metody fit oraz predict.
W powyższym zapisie, dostarczyliśmy dwa transformatory scikit-learn - StandardScaler i PCA oraz estymator LogisticRegression jako dane wejściowe do funkcji make_pipeline, która konstruuje obiekt scikit-learn Pipeline z tych obiektów.
Na końcu zwracamy prognozę na podstawie przekształconych danych.
pipe_lr.fit(X_train, y_train)
y_pred = pipe_lr.predict(X_test)
confmat = confusion_matrix(y_true = y_test, y_pred = y_pred)
print(confmat)
[[300 26] [ 33 403]]
fig, ax = plt.subplots(figsize = (2.5, 2.5))
ax.matshow(confmat, cmap = plt.cm.Blues, alpha = 0.3)
for i in range(confmat.shape[0]):
for j in range(confmat.shape[1]):
ax.text(x = j, y = i, s = confmat[i, j],
va = 'center', ha = 'center')
ax.xaxis.set_ticks_position('bottom')
plt.xlabel('Predicted label')
plt.ylabel('True label')
plt.show()
scores_lr = cross_val_score(estimator = pipe_lr,
X = X_train,
y = y_train,
cv = 10,
n_jobs = 1)
print(f'CV accuracy scores: {scores_lr}')
print(f'CV accuracy scores: {np.mean(scores_lr):.3f}'
f' +/- {np.std(scores_lr):.3f}')
CV accuracy scores: [0.92786885 0.93770492 0.90819672 0.91803279 0.9147541 0.94754098 0.92131148 0.9147541 0.92763158 0.91447368] CV accuracy scores: 0.923 +/- 0.011
Zarówno błąd predykcji (ERR), jak i dokładność (ACC) dostarczają ogólnych informacji o tym, ile przykładów zostało błędnie sklasyfikowanych. Błąd można rozumieć jako sumę wszystkich fałszywych przewidywań podzieloną przez liczbę przez liczbę całkowitych przewidywań, a dokładność jest obliczana jako suma poprawnych przewidywań podzielona przez całkowitą liczbę przewidywań. podzielona odpowiednio przez całkowitą liczbę przewidywań: $$ ERR = \frac{FP + FN}{FP + FN + TP + TN}$$
Dokładność predykcji można następnie obliczyć bezpośrednio na podstawie błędu: $$ ACC = \frac{TP + TN}{FP + FN + TP + TN} = 1 - ERR $$
Współczynnik wyników prawdziwie pozytywnych (True Positive Rate) i współczynnik wyników fałszywie pozytywnych (False Positive Rate) to wskaźniki wydajności, które są szczególnie przydatne w przypadku problemów z niezrównoważonymi klasami: $$ FPR = \frac{FP}{N} = \frac{FP}{FP+TN}$$ $$ TPR = \frac{TP}{P} = \frac{TP}{FN + TP}$$
Wskaźniki wydajności precyzji (PRE) i wycofania (REC) są powiązane z tymi wskaźnikami TP i TN, i w rzeczywistości REC jest synonimem TPR:
$$ REC = TPR = \frac{TP}{P} = \frac{TP}{FN + TP} $$Innymi słowy, przywołanie określa ilościowo, ile odpowiednich rekordów (pozytywnych) zostało przechwyconych jako takie (prawdziwe pozytywne). Precyzja określa, ile rekordów przewidywanych jako istotne (suma prawdziwych i fałszywych wyników pozytywnych) jest faktycznie istotnych (prawdziwe wyniki pozytywne):
$$ PRE = \frac{TP}{TP + FP}$$Aby zrównoważyć wady i zalety optymalizacji PRE i REC, stosuje się średnią harmoniczną PRE i REC tak zwany wynik F1:
$$ F1 = 2 \frac{PRE \times REC}{PRE + REC}$$Miarą podsumowującą macierz pomyłek jest MCC. MCC oblicza się w następujący sposób: $$ MCC = \frac{TP \times TN - FP \times FN}{\sqrt{(TP + FP)(TP + FN)(TP + FP)(TN + FN)}}$$
W przeciwieństwie do PRE, REC i wyniku F1, MCC mieści się w zakresie od -1 do 1 i uwzględnia wszystkie elementy macierzy pomyłek - na przykład wynik F1 nie obejmuje TN.
Chociaż wartości MCC są trudniejsze do zinterpretowania niż wynik F1, jest on uważany za lepszy wskaźnik, jak opisano w poniższym artykule: The advantages of the Matthews correlation coefficient (MCC) over F1 score and accuracy in binary classification evaluation autorstwa D. Chicco i G. Jurman, BMC Genomics. s. 281-305, 2012, https://bmcgenomics.biomedcentral.com/articles/10.1186/s1 864-019-6413-7.
Wszystkie te metryki punktacji są zaimplementowane w scikit-learn i mogą być importowane z modułu sklearn. metrics, jak pokazano w poniższym fragmencie:
pre_val_lr = precision_score(y_true = y_test, y_pred = y_pred)
print(f'Precision: {pre_val_lr}')
rec_val_lr = recall_score(y_true = y_test, y_pred = y_pred)
print(f'Recall: {rec_val_lr}')
f1_val_lr = f1_score(y_true = y_test, y_pred = y_pred)
print(f'F1: {f1_val_lr}')
mcc_val_lr = matthews_corrcoef(y_true = y_test, y_pred = y_pred)
print(f'MCC: {mcc_val_lr:.3f}')
Precision: 0.9393939393939394 Recall: 0.9243119266055045 F1: 0.9317919075144507 MCC: 0.842
Krzywe ROC - ang.Receiver operating characteristic (ROC) są przydatnymi narzędziami do wyboru modeli do klasyfikacji na podstawie ich wydajności w odniesieniu do FPR i TPR, które są obliczane przez przesunięcie progu decyzyjnego klasyfikatora.
Przekątna wykresu ROC może być interpretowana jako losowe zgadywanie, a modele klasyfikacji, które spadają poniżej przekątnej, są uważane za gorsze niż losowe zgadywanie.
Idealny klasyfikator znalazłby się w lewym górnym rogu wykresu z TPR równym 1 i FPR równym 0. Na podstawie krzywej ROC możemy następnie obliczyć tak zwany obszar ROC pod krzywą (ROC AUC), aby scharakteryzować wydajność modelu klasyfikacji.
Wykonując poniższy przykład kodu, wykreślimy krzywą ROC klasyfikatora, który wykorzystuje tylko dwie cechy ze zbioru danych, aby przewidzieć, czy ryż jest klasy Cammeo, czy Osmancik. Chociaż zamierzamy użyć tego samego pipeline'u regresji logistycznej, który zdefiniowaliśmy wcześniej, tym razem używamy tylko dwóch cech. Ma to na celu uczynienie zadania klasyfikacji trudniejszym dla klasyfikatora, poprzez wstrzymanie przydatnych informacji zawartych w innych cechach, tak aby wynikowa krzywa ROC stała się bardziej interesująca wizualnie. Z podobnych powodów zmniejszamy również liczbę podziałów w walidatorze StratifiedKFold do trzech.
Kod wygląda następująco:
pipe_lr = make_pipeline(
StandardScaler(),
PCA(n_components = 2),
LogisticRegression(penalty = 'l2', random_state = 1,
solver = 'lbfgs', C = 100.0)
)
X_train2 = X_train[:, [1, 2]]
cv = list(StratifiedKFold(n_splits=3).split(X_train, y_train))
fig = plt.figure(figsize=(7, 5))
mean_tpr = 0.0
mean_fpr = np.linspace(0, 1, 100)
all_tpr = []
for i, (train, test) in enumerate(cv):
probas = pipe_lr.fit(
X_train2[train],
y_train[train]).predict_proba(X_train2[test])
fpr, tpr, thresholds = roc_curve(y_train[test],
probas[:, 1],
pos_label=1)
mean_tpr += interp(mean_fpr, fpr, tpr)
mean_tpr[0] = 0.0
roc_auc = auc(fpr, tpr)
plt.plot(fpr,
tpr,
label=f'ROC fold {i+1} (area = {roc_auc:.2f})')
plt.plot([0, 1],
[0, 1],
linestyle='--',
color=(0.6, 0.6, 0.6),
label='Random guessing (area=0.5)')
mean_tpr /= len(cv)
mean_tpr[-1] = 1.0
mean_auc = auc(mean_fpr, mean_tpr)
plt.plot(mean_fpr, mean_tpr, 'k--',
label=f'Mean ROC (area = {mean_auc:.2f})', lw=2)
plt.plot([0, 0, 1],
[0, 1, 1],
linestyle=':',
color='black',
label='Perfect performance (area=1.0)')
plt.xlim([-0.05, 1.05])
plt.ylim([-0.05, 1.05])
plt.xlabel('False positive rate')
plt.ylabel('True positive rate')
plt.legend(loc='lower right')
plt.show()
W kodzie użyliśmy znanej już klasy StratifiedKFold z scikit-learn i obliczyliśmy wydajność ROC klasyfikatora LogisticRegression w naszym potoku pipe_lr przy użyciu funkcji roc_curve z modułu sklearn.metrics oddzielnie dla każdej iteracji. Ponadto interpolowaliśmy średnią krzywą ROC z trzech zagięć za pomocą funkcji interp, którą zaimportowaliśmy z NumPy i obliczyliśmy obszar pod krzywą za pomocą funkcji AUC.
Wynikowa krzywa ROC wskazuje, że występuje duża zbieżność między różnymi podziałami, a średnia wartość ROC AUC (0,98) mieści się pomiędzy idealnym wynikiem (1,0) a losowym zgadywaniem (0,5).
Zauważmy, że jeśli interesuje nas tylko wynik ROC AUC, możemy również bezpośrednio zaimportować funkcję roc_auc_score z podmodułu sklearn.metrics, która może być używana podobnie do innych funkcji punktacji (na przykład precision_score).
Raportowanie wydajności klasyfikatora jako ROC AUC może dostarczyć dalszych informacji na temat wydajności klasyfikatora w odniesieniu do niezrównoważonych próbek.
Jednakże, podczas gdy wynik dokładności może być interpretowany jako pojedynczy punkt odcięcia na krzywej ROC, A. P. Bradley wykazał, że wskaźniki ROC AUC i dokładności w większości zgadzają się ze sobą: The Use of the Area Under the ROC Curve in the Evaluation of Machine Learning Algorithms by A. P. Bradley, Pattern Recognition, 30(7): 1145-1159, 1997, https://reader.elsevier.com/reader/sd/pii/S0031320396001422
Tutatj przedstawiamy działanie krzywej uczenia się i krzywej walidacji do zdiagnozowania. Przyjrzymy się, czy algorytm ma problem z nadmiernym dopasowaniem (wysoka wariancja) lub też niedostatecznym dopasowaniem (wysokie odchylenie).
Jeśli model jest zby złożony dla danego zbioru danych treningowych - model ma wtedy tendencję do nadmiernego dopasowywania danych szkoleniowych i nie uogólnia się dobrze na niewidoczne dane.
Często pomocne może być zebranie większej liczby przykładów szkoleniowych, aby zmniejszyć stopień nadmiernego dopasowania.
Jednak w praktyce gromadzenie większej ilości danych może być często bardzo kosztowne lub po prostu niewykonalne.
Poprzez wykreślenie dokładności modelu treningowego i walidacyjnego jako funkcji wielkości zbioru danych treningowych, możemy łatwo wykryć, czy model cierpi z powodu dużej wariancji lub dużej stronniczości i czy zebranie większej ilości danych może pomóc w rozwiązaniu tego problemu.
Zobaczmy, jak możemy użyć funkcji krzywej uczenia się z scikit-learn do oceny modelu:
pipe_lr = make_pipeline(StandardScaler(),
LogisticRegression(penalty='l2',
max_iter=10000))
train_sizes, train_scores, test_scores = \
learning_curve(estimator=pipe_lr,
X=X_train,
y=y_train,
train_sizes=np.linspace(
0.1, 1.0, 10),
cv=10,
n_jobs=1)
train_mean = np.mean(train_scores, axis=1)
train_std = np.std(train_scores, axis=1)
test_mean = np.mean(test_scores, axis=1)
test_std = np.std(test_scores, axis=1)
plt.plot(train_sizes, train_mean,
color='blue', marker='o',
markersize=5, label='Training accuracy')
plt.fill_between(train_sizes,
train_mean + train_std,
train_mean - train_std,
alpha=0.15, color='blue')
plt.plot(train_sizes, test_mean,
color='green', linestyle='--',
marker='s', markersize=5,
label='Validation accuracy')
plt.fill_between(train_sizes,
test_mean + test_std,
test_mean - test_std,
alpha=0.15, color='green')
plt.grid()
plt.xlabel('Number of training examples')
plt.ylabel('Accuracy')
plt.legend(loc='lower right')
plt.ylim([0.5, 1.05])
plt.show()
Przekazaliśmy max_iter = 10000 jako dodatkowy argument, podczas tworzenia instancji obiektu LogisticRegression (który domyślnie używa 1000 iteracji), aby uniknąć problemów ze zbieżnością dla mniejszych rozmiarów zbiorów danych lub ekstremalnych wartości parametrów regularyzacji.
Za pomocą parametru train_sizes w funkcji learning_curve możemy kontrolować bezwzględną lub względną liczbę przykładów treningowych, które są używane do generowania krzywych uczenia się.
Tutaj ustaliliśmy train_sizes = np.linspace(0.1,1.0,10), aby użyć 10 równomiernie rozmieszczonych względnych przedziałów dla rozmiarów zbioru danych treningowych.
Domyślnie funkcja learning_curve wykorzystuje k-krotną waldację krzyżową do obliczenia dokładności walidacji krzyżowej klasyfikatora, a my ustawiamy $k = 10$ za pomocą parametru cv dla 10-krotnej warstwowej walidacji krzyżowej.
Następnie po prostu obliczamy średnią dokładność na podstawie zwróconych zweryfikowanych krzyżowo wyników treningowych i testowych dla różnych rozmiarów zbioru danych treningowych, które wykreśliliśmy za pomocą funkcji wykresu Matplotlib.
Ponadto dodaliśmy odchylenie standardowe średniej dokładności do wykresu za pomocą funkcji fill_between aby wskazać wariancję oszacowania.
Jak widzimy na poprzednim wykresie krzywej uczenia, nasz model radzi sobie bardzo dobrze zarówno na zbiorze danych treningowych, jak i walidacyjnych.
Krzywe walidacyjne są przydatnym narzędziem do poprawy wydajności modelu poprzez rozwiązywanie problemów takich jak nadmierne lub niedostateczne dopasowanie.
Krzywe walidacji są powiązane z krzywymi uczenia się, ale zamiast wykreślać jako funkcji wielkości próby, zmieniamy wartości parametrów modelu, na przykład odwrotny parametr regularyzacji, C, w regresji logistycznej.
param_range = [0.001, 0.01, 0.1, 1.0, 10.0, 100.0]
train_scores, test_scores = validation_curve(
estimator = pipe_lr,
X = X_train,
y = y_train,
param_name = 'logisticregression__C',
param_range = param_range,
cv = 10)
train_mean = np.mean(train_scores , axis = 1)
train_std = np.std(train_scores, axis = 1)
test_mean = np.mean(test_scores, axis = 1)
test_std = np.std(test_scores, axis = 1)
plt.plot(param_range, train_mean, color = 'blue',
marker = 'o', markersize = 5,
label = 'Training accuracy')
plt.fill_between(param_range, train_mean + train_std,
train_mean - train_std, alpha = 0.15,
color = 'blue')
plt.plot(param_range, test_mean,
color = 'green', linestyle = '--',
marker = 's', markersize = 5,
label = 'Validation accuracy')
plt.fill_between(param_range,
test_mean + test_std,
test_mean - test_std,
alpha = 0.15, color = 'green')
plt.grid()
plt.xscale('log')
plt.legend(loc = 'lower right')
plt.xlabel('Parameter C')
plt.ylabel('Accuracy')
plt.ylim([0.5, 1.05])
plt.show()
Podobnie jak funkcja learning_curve, funkcja validation_curve domyślnie wykorzystuje warstwową k-krotną walidację krzyżową do oszacowania wydajności klasyfikatora.
Wewnątrz funkcji validation_curve określiliśmy parametr, który chcieliśmy ocenić. W tym przypadku jest to C, odwrotny parametr regularyzacji klasyfikatora LogisticRegression, który zapisaliśmy jako logisticregression__C.
Aby uzyskać dostęp do obiektu LogisticRegression wewnątrz potoku scikit-learn dla określonego zakresu wartości, który ustawiliśmy za pomocą parametru param_range.
Podobnie jak w przykładzie krzywej uczenia się w poprzedniej sekcji, wykreśliliśmy średnią dokładność treningu i walidacji krzyżowej oraz odpowiadające im odchylenia standardowe.
Widzimy, że dla dowolnego C, model dobrze dopasowywuje się do danych.
Wykorzystamy teraz technikę optymalizacji hiperparametrów (parametry algorytmu uczącego poddane osobnej optymalizacji) zwanej przeszukiwaniem siatki (Grid Search), która może dodatkowo pomóc poprawić wydajność modelu, poprzez znalezienie ich optymalnej kombinacji wartości.
Działanie Grid Searchu jest następujące: jest to paradygmat brutalnego wyszukiwania wyczerpującego, w którym określamy listę wartości dla różnych hiperparametrów, a komputer ocenia wydajność modelu dla każdej kombinacji, aby uzyskać optymalną kombinację wartości z tego zestawu.
# Tworzenie potoku z użyciem LogisticRegression i StandardScaler
pipe_lr = make_pipeline(StandardScaler(), LogisticRegression(max_iter=10000, random_state=1))
# Definiowanie zakresu hiperparametrów
param_grid = {
'logisticregression__C': [0.001, 0.01, 0.1, 1.0, 10.0, 100.0], # Zakres parametru regularyzacji C
'logisticregression__solver': ['liblinear', 'lbfgs', 'sag', 'saga'] # Wybór solvera
}
# Przeprowadzenie przeszukiwania siatki
gs_lr = GridSearchCV(estimator=pipe_lr,
param_grid=param_grid,
scoring='accuracy',
cv=10,
n_jobs=-1)
gs_lr = gs_lr.fit(X_train, y_train)
# Wyświetlenie najlepszego wyniku i najlepszych parametrów
print(gs_lr.best_score_)
print(gs_lr.best_params_)
0.9314279551337359
{'logisticregression__C': 10.0, 'logisticregression__solver': 'sag'}
Zainicjowaliśmy obiekt GridSearchCV z modułu sklearn.model_selection do trenowania i dostrajania potoku LogisticRegression.
Ustawiliśmy parametr param_grid obiektu GridSearchCV na listę słowników, aby określić parametry, które chcemy dostroić.
GridSearchCV wykorzystuje k-krotną walidację krzyżową do porównywania modeli wytrenowanych z różnymi ustawieniami hiperparametrów.
Poprzez ustawienie cv = 10, przeprowadzi 10-krotną walidację krzyżową i obliczy średnią dokładność (poprzez scoring='accuracy') w tych 10-krotnościach, aby ocenić wydajność modelu.
Ustawiliśmy n_jobs=-1, aby GridSearchCV mógł wykorzystać wszystkie nasze rdzenie przetwarzające w celu przyspieszenia wyszukiwania siatki poprzez równoległe dopasowywanie modeli do różnych podziałów.
Po wykorzystaniu danych treningowych do przeprowadzenia wyszukiwania siatki uzyskaliśmy wynik najlepiej działającego modelu za pośrednictwem atrybutu best_score_ i przyjrzeliśmy się jego parametrom, do których można uzyskać dostęp za pośrednictwem atrybutu best_params_.
W tym konkretnym przypadku solver sag z logisticregression__C = 10 uzyskał najlepszą dokładność k-kronej walidacji krzyżowej na poziomie $93\%$.
Na koniec wykorzystujemy niezależny zestaw danych testowych do oszacowania wydajności najlepiej wybranego modelu, który jest dostępny za pośrednictwem atrybutu best_estimator_ obiektu GridSearchCV
clf_lr = gs_lr.best_estimator_
clf_lr.fit(X_train, y_train)
print(f'Test accuracy: {clf_lr.score(X_test, y_test):.3f}')
Test accuracy: 0.924
Co więcej, możemy użyć innej metryki punktacji niż dokładność w GridSearchCV poprzez parametr scoring parametr.
scorer = make_scorer(f1_score, pos_label = 0)
gs = GridSearchCV(estimator = pipe_lr,
param_grid = param_grid,
scoring = scorer,
cv = 2)
gs = gs.fit(X_train, y_train)
print(gs.best_score_)
print(gs.best_params_)
0.9210531934579306
{'logisticregression__C': 100.0, 'logisticregression__solver': 'sag'}
Korzystanie z k-krotnej walidacji krzyżowej w połączeniu z wyszukiwaniem siatki lub wyszukiwaniem randomizowanym jest użytecznym podejściem do dostrajania wydajności modelu uczenia maszynowego poprzez zmianę jego wartości hiperparametrów.
Jeśli jednak chcemy wybrać inny algoryt uczenia maszynowego, zalecanym podejściem jest zagnieżdżona walidacja krzyżowa.
W ciekawym badaniu na temat stronniczości w szacowaniu błędów, Sudhir Varma i Richard Simon doszli do wniosku, że prawdziwy błąd oszacowania jest prawie bezstronny w stosunku do zbioru danych testowych, gdy stosowana jest zagnieżdżona walidacja krzyżowa (Bias in Error Estimation When Using Cross-Validation for Model Selection by S. Varma and R. Simon, BMC Bioinformatics, 7(1): 91, 2006, https://bmcbioinformatics.biomedcentral.com/articl es/10.1186/1471-2105-7-91).
W zagnieżdżonej walidacji krzyżowej mamy zewnętrzną pętlę k-krotnej walidacji krzyżowej, aby podzielić dane na podziały treningowe i testowe, a wewnętrzna pętla służy do wyboru modelu przy użyciu k-krotnej walidacji krzyżowej na podziale treningowym. Po wyborze modelu, podział testowy jest następnie wykorzystywany do oceny wydajności modelu.
W scikit-learn możemy przeprowadzić zagnieżdżoną walidację krzyżową z wyszukiwaniem siatki w następujący sposób:
nested_gs_lr = GridSearchCV(estimator = pipe_lr,
param_grid = param_grid,
scoring = 'accuracy',
cv = 2)
nested_scores_lr = cross_val_score(nested_gs_lr, X_train, y_train,
scoring = 'accuracy', cv = 5)
print(f'CV accuracy: {np.mean(nested_scores_lr):.3f}'
f' +/- {np.std(nested_scores_lr):.3f}')
CV accuracy: 0.930 +/- 0.010
Zwrócona średnia dokładność walidacji krzyżowej daje nam dobre oszacowanie tego, czego możemy się spodziewać, jeśli dostroimy hiperparametry modelu i użyjemy go na niewidocznych danych.
Pakiet scikit-learn implementuje klasę RandomizedSearchCV, która jest analogiczna do GridSearchCV. Główną różnicą jest to, że możemy określić dystrybucje jako część naszej siatki parametrów i określić całkowitą liczbę konfiguracji hiperparametrów do oceny.
Na przykład, rozważmy zakres hiperparametrów, którego użyliśmy dla kilku hiperparametrów podczas dostrajania Logistic Regression w przykładzie wcześniej wspomnianego wyszukiwania siatki.
# Tworzenie potoku z użyciem StandardScaler i LogisticRegression
pipe_lr = make_pipeline(StandardScaler(), LogisticRegression(max_iter=10000, random_state=1))
# Definiowanie zakresu hiperparametrów
param_dist = {
'logisticregression__C': [0.001, 0.01, 0.1, 1.0, 10.0, 100.0], # Zakres parametru regularyzacji C
'logisticregression__solver': ['liblinear', 'lbfgs', 'sag', 'saga'] # Wybór solvera
}
# Przeprowadzenie przeszukiwania losowego
rs_lr = RandomizedSearchCV(estimator=pipe_lr,
param_distributions=param_dist,
scoring='accuracy',
n_iter=20,
cv=10,
refit=True,
random_state=1,
n_jobs=-1)
rs_lr.fit(X_train, y_train)
# Wyświetlenie najlepszego wyniku i najlepszych parametrów
print(rs_lr.best_score_)
print(rs_lr.best_params_)
0.9314279551337359
{'logisticregression__solver': 'sag', 'logisticregression__C': 10.0}
# Tworzenie obiektu SVM
svm = SVC(kernel = 'linear', C = 10.0, random_state = 1)
# Dopasowanie modelu SVM do danych z PCA
svm.fit(X_train_pca, y_train)
# Wizualizacja wyników na zbiorze treningowym po PCA
plot_decision_regions(X_train_pca, y_train, classifier=svm)
plt.xlabel('PC 1')
plt.ylabel('PC 2')
plt.legend(loc='best')
plt.tight_layout()
plt.show()
# Wizualizacja wyników na zbiorze testowym po PCA
plot_decision_regions(X_test_pca, y_test, classifier=svm)
plt.xlabel('PC 1')
plt.ylabel('PC 2')
plt.legend(loc='best')
plt.tight_layout()
plt.show()
pipe_svc = make_pipeline(StandardScaler(),
SVC(kernel = 'linear',
C = 10.0,
random_state=1))
pipe_svc.fit(X_train, y_train)
y_pred = pipe_svc.predict(X_test)
test_acc_svc = pipe_svc.score(X_test, y_test)
print(f'Test accuracy: {test_acc_svc: .3f}')
Test accuracy: 0.920
pipe_svc.fit(X_train, y_train)
y_pred = pipe_svc.predict(X_test)
confmat = confusion_matrix(y_true = y_test, y_pred = y_pred)
print(confmat)
[[297 29] [ 32 404]]
fig, ax = plt.subplots(figsize = (2.5, 2.5))
ax.matshow(confmat, cmap = plt.cm.Blues, alpha = 0.3)
for i in range(confmat.shape[0]):
for j in range(confmat.shape[1]):
ax.text(x = j, y = i, s = confmat[i, j],
va = 'center', ha = 'center')
ax.xaxis.set_ticks_position('bottom')
plt.xlabel('Predicted label')
plt.ylabel('True label')
plt.show()
scores_svc = cross_val_score(estimator = pipe_svc,
X = X_train,
y = y_train,
cv = 10,
n_jobs = 1)
print(f'CV accuracy scores: {scores_svc}')
print(f'CV accuracy scores: {np.mean(scores_svc):.3f}'
f' +/- {np.std(scores_svc):.3f}')
CV accuracy scores: [0.93442623 0.93770492 0.91803279 0.93770492 0.93442623 0.96065574 0.93442623 0.9147541 0.91776316 0.92434211] CV accuracy scores: 0.931 +/- 0.013
pre_val_svc = precision_score(y_true = y_test, y_pred = y_pred)
print(f'Precision: {pre_val_svc}')
rec_val_svc = recall_score(y_true = y_test, y_pred = y_pred)
print(f'Recall: {rec_val_svc}')
f1_val_svc = f1_score(y_true = y_test, y_pred = y_pred)
print(f'F1: {f1_val_svc}')
mcc_val_svc = matthews_corrcoef(y_true = y_test, y_pred = y_pred)
print(f'MCC: {mcc_val_svc:.3f}')
Precision: 0.9330254041570438 Recall: 0.926605504587156 F1: 0.9298043728423475 MCC: 0.837
# Tworzenie potoku z użyciem SVC i StandardScaler
pipe_svc = make_pipeline(StandardScaler(), SVC(kernel = 'linear', C = 10.0, probability=True, random_state=1))
# Podział danych do walidacji krzyżowej
cv = list(StratifiedKFold(n_splits=3).split(X_train, y_train))
# Inicjalizacja wykresu
fig = plt.figure(figsize=(7, 5))
mean_fpr = np.linspace(0, 1, 100)
all_tpr = []
# Dla każdego podziału walidacji krzyżowej
for i, (train, test) in enumerate(cv):
# Dopasowanie modelu do danych treningowych
probas = pipe_svc.fit(X_train[train], y_train[train]).predict_proba(X_train[test])
# Obliczenie współczynników True Positive Rate (TPR) oraz False Positive Rate (FPR)
fpr, tpr, thresholds = roc_curve(y_train[test], probas[:, 1], pos_label=1)
# Interpolacja wyników na średnią krzywą ROC
mean_tpr = np.interp(mean_fpr, fpr, tpr)
mean_tpr[0] = 0.0
all_tpr.append(mean_tpr)
# Obliczenie pola pod krzywą ROC (AUC)
roc_auc = auc(fpr, tpr)
# Wyświetlenie krzywej ROC dla każdego podziału
plt.plot(fpr, tpr, label=f'ROC fold {i+1} (area = {roc_auc:.2f})')
# Obliczenie średniego True Positive Rate
mean_tpr = np.mean(all_tpr, axis=0)
mean_tpr[-1] = 1.0
# Obliczenie średniego pola pod krzywą ROC (AUC)
mean_auc = auc(mean_fpr, mean_tpr)
# Wyświetlenie średniej krzywej ROC
plt.plot(mean_fpr, mean_tpr, 'k--', label=f'Mean ROC (area = {mean_auc:.2f})', lw=2)
# Wyświetlenie linii referencyjnych
plt.plot([0, 1], [0, 1], linestyle='--', color=(0.6, 0.6, 0.6), label='Random guessing (area=0.5)')
plt.plot([0, 0, 1], [0, 1, 1], linestyle=':', color='black', label='Perfect performance (area=1.0)')
# Ustawienia osi i legendy
plt.xlim([-0.05, 1.05])
plt.ylim([-0.05, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.legend(loc='lower right')
plt.tight_layout()
plt.show()
# Tworzenie potoku z użyciem StandardScaler i SVC
pipe_svc = make_pipeline(StandardScaler(), SVC(kernel='rbf', random_state=1))
# Wygenerowanie krzywej uczenia
train_sizes, train_scores, test_scores = learning_curve(estimator=pipe_svc,
X=X_train,
y=y_train,
train_sizes=np.linspace(0.1, 1.0, 10),
cv=10,
n_jobs=1)
# Obliczenie średnich i odchyleń standardowych dokładności dla danych treningowych i testowych
train_mean = np.mean(train_scores, axis=1)
train_std = np.std(train_scores, axis=1)
test_mean = np.mean(test_scores, axis=1)
test_std = np.std(test_scores, axis=1)
# Wykreślenie krzywej uczenia
plt.plot(train_sizes, train_mean,
color='blue', marker='o',
markersize=5, label='Training accuracy')
plt.fill_between(train_sizes,
train_mean + train_std,
train_mean - train_std,
alpha=0.15, color='blue')
plt.plot(train_sizes, test_mean,
color='green', linestyle='--',
marker='s', markersize=5,
label='Validation accuracy')
plt.fill_between(train_sizes,
test_mean + test_std,
test_mean - test_std,
alpha=0.15, color='green')
plt.grid()
plt.xlabel('Number of training examples')
plt.ylabel('Accuracy')
plt.legend(loc='lower right')
plt.ylim([0.8, 1.0])
plt.show()
pipe_svc = make_pipeline(StandardScaler(), SVC(kernel='rbf', random_state=1))
param_range = [0.001, 0.01, 0.1, 1.0, 10.0, 100.0]
# Wygeneruj krzywą walidacji dla parametru C w SVC
train_scores, test_scores = validation_curve(estimator=pipe_svc,
X=X_train,
y=y_train,
param_name='svc__C',
param_range=param_range,
cv=10)
train_mean = np.mean(train_scores, axis=1)
train_std = np.std(train_scores, axis=1)
test_mean = np.mean(test_scores, axis=1)
test_std = np.std(test_scores, axis=1)
# Wykreśl krzywą walidacji
plt.plot(param_range, train_mean,
color='blue', marker='o',
markersize=5, label='Training accuracy')
plt.fill_between(param_range, train_mean + train_std,
train_mean - train_std, alpha=0.15,
color='blue')
plt.plot(param_range, test_mean,
color='green', linestyle='--',
marker='s', markersize=5,
label='Validation accuracy')
plt.fill_between(param_range,
test_mean + test_std,
test_mean - test_std,
alpha=0.15, color='green')
plt.grid()
plt.xscale('log')
plt.legend(loc='lower right')
plt.xlabel('Parameter C')
plt.ylabel('Accuracy')
plt.ylim([0.8, 1.0])
plt.title('Validation Curve for SVM')
plt.show()
pipe_svc = make_pipeline(StandardScaler(),
SVC(random_state = 1))
param_range = [0.001, 0.01, 0.1,
1.0, 10.0, 100.0]
param_grid = [{'svc__C': param_range,
'svc__kernel': ['linear']},
{'svc__C': param_range,
'svc__gamma': param_range,
'svc__kernel':['rbf']}]
gs_svc = GridSearchCV(estimator = pipe_svc,
param_grid = param_grid,
scoring = 'accuracy',
cv = 10,
refit = True,
n_jobs = -1)
gs_svc = gs_svc.fit(X_train, y_train)
print(gs_svc.best_score_)
print(gs_svc.best_params_)
0.9314236410698877
{'svc__C': 10.0, 'svc__kernel': 'linear'}
clf_svc = gs_svc.best_estimator_
clf_svc.fit(X_train, y_train)
print(f'Test accuracy: {clf_svc.score(X_test, y_test):.3f}')
Test accuracy: 0.920
scorer = make_scorer(f1_score, pos_label = 0)
gs = GridSearchCV(estimator = pipe_svc,
param_grid = param_grid,
scoring = scorer,
cv = 2)
gs = gs.fit(X_train, y_train)
print(gs.best_score_)
print(gs.best_params_)
0.9204763085497031
{'svc__C': 10.0, 'svc__kernel': 'linear'}
nested_gs_svc = GridSearchCV(estimator = pipe_svc,
param_grid = param_grid,
scoring = 'accuracy',
cv = 2)
nested_scores_svc = cross_val_score(nested_gs_svc, X_train, y_train,
scoring = 'accuracy', cv = 5)
print(f'CV accuracy: {np.mean(nested_scores_svc):.3f}'
f' +/- {np.std(nested_scores_svc):.3f}')
CV accuracy: 0.930 +/- 0.010
pipe_svc = make_pipeline(StandardScaler(),
SVC(random_state = 1))
param_dist = [{'svc__C': param_range,
'svc__kernel': ['linear']},
{'svc__C': param_range,
'svc__gamma': param_range,
'svc__kernel':['rbf']}]
rs_svc = RandomizedSearchCV(estimator=pipe_svc,
param_distributions=param_dist,
scoring='accuracy',
refit=True,
n_iter=20,
cv=10,
random_state=1,
n_jobs=-1)
rs_svc = rs_svc.fit(X_train, y_train)
print(rs_svc.best_score_)
print(rs_svc.best_params_)
0.9314236410698877
{'svc__kernel': 'linear', 'svc__C': 10.0}
# Tworzenie obiektu klasyfikatora drzewa decyzyjnego
tree = DecisionTreeClassifier(criterion='gini', max_depth=3, random_state=1)
# Dopasowanie modelu do danych PCA
tree.fit(X_train_pca, y_train)
# Wizualizacja wyników na zbiorze treningowym po PCA
plot_decision_regions(X_train_pca, y_train, classifier=tree)
plt.xlabel('PC 1')
plt.ylabel('PC 2')
plt.legend(loc='best')
plt.tight_layout()
plt.show()
# Wizualizacja wyników na zbiorze testowym po PCA
plot_decision_regions(X_test_pca, y_test, classifier=tree)
plt.xlabel('PC 1')
plt.ylabel('PC 2')
plt.legend(loc='best')
plt.tight_layout()
plt.show()
# Utwórz potok zawierający StandardScaler i DecisionTreeClassifier
pipe_dt = make_pipeline(StandardScaler(), DecisionTreeClassifier(random_state=1))
# Trenuj model na danych treningowych
pipe_dt.fit(X_train, y_train)
# Dokonaj predykcji na danych testowych
y_pred_dt = pipe_dt.predict(X_test)
# Oblicz dokładność modelu na danych testowych
test_acc_dt = pipe_dt.score(X_test, y_test)
print(f'Test accuracy (DecisionTreeClassifier): {test_acc_dt:.3f}')
Test accuracy (DecisionTreeClassifier): 0.888
pipe_dt.fit(X_train, y_train)
y_pred = pipe_dt.predict(X_test)
confmat = confusion_matrix(y_true = y_test, y_pred = y_pred)
print(confmat)
[[288 38] [ 47 389]]
fig, ax = plt.subplots(figsize = (2.5, 2.5))
ax.matshow(confmat, cmap = plt.cm.Blues, alpha = 0.3)
for i in range(confmat.shape[0]):
for j in range(confmat.shape[1]):
ax.text(x = j, y = i, s = confmat[i, j],
va = 'center', ha = 'center')
ax.xaxis.set_ticks_position('bottom')
plt.xlabel('Predicted label')
plt.ylabel('True label')
plt.show()
scores_dt = cross_val_score(estimator = pipe_dt,
X = X_train,
y = y_train,
cv = 10,
n_jobs = 1)
print(f'CV accuracy scores: {scores_dt}')
print(f'CV accuracy scores: {np.mean(scores_dt):.3f}'
f' +/- {np.std(scores_dt):.3f}')
CV accuracy scores: [0.89836066 0.90163934 0.8852459 0.90491803 0.89836066 0.89180328 0.89508197 0.88196721 0.875 0.85526316] CV accuracy scores: 0.889 +/- 0.014
pre_val_dt = precision_score(y_true = y_test, y_pred = y_pred)
print(f'Precision: {pre_val_dt}')
rec_val_dt = recall_score(y_true = y_test, y_pred = y_pred)
print(f'Recall: {rec_val_dt}')
f1_val_dt = f1_score(y_true = y_test, y_pred = y_pred)
print(f'F1: {f1_val_dt}')
mcc_val_dt = matthews_corrcoef(y_true = y_test, y_pred = y_pred)
print(f'MCC: {mcc_val_dt:.3f}')
Precision: 0.9110070257611241 Recall: 0.8922018348623854 F1: 0.9015063731170336 MCC: 0.773
# Podział danych do walidacji krzyżowej
cv = list(StratifiedKFold(n_splits=3).split(X_train, y_train))
# Inicjalizacja wykresu
fig = plt.figure(figsize=(7, 5))
mean_fpr = np.linspace(0, 1, 100)
all_tpr = []
# Dla każdego podziału walidacji krzyżowej
for i, (train, test) in enumerate(cv):
# Dopasowanie modelu do danych treningowych
probas = pipe_dt.fit(X_train[train], y_train[train]).predict_proba(X_train[test])
# Obliczenie współczynników True Positive Rate (TPR) oraz False Positive Rate (FPR)
fpr, tpr, thresholds = roc_curve(y_train[test], probas[:, 1], pos_label=1)
# Interpolacja wyników na średnią krzywą ROC
mean_tpr = np.interp(mean_fpr, fpr, tpr)
mean_tpr[0] = 0.0
all_tpr.append(mean_tpr)
# Obliczenie pola pod krzywą ROC (AUC)
roc_auc = auc(fpr, tpr)
# Wyświetlenie krzywej ROC dla każdego podziału
plt.plot(fpr, tpr, label=f'ROC fold {i+1} (area = {roc_auc:.2f})')
# Obliczenie średniego True Positive Rate
mean_tpr = np.mean(all_tpr, axis=0)
mean_tpr[-1] = 1.0
# Obliczenie średniego pola pod krzywą ROC (AUC)
mean_auc = auc(mean_fpr, mean_tpr)
# Wyświetlenie średniej krzywej ROC
plt.plot(mean_fpr, mean_tpr, 'k--', label=f'Mean ROC (area = {mean_auc:.2f})', lw=2)
# Wyświetlenie linii referencyjnych
plt.plot([0, 1], [0, 1], linestyle='--', color=(0.6, 0.6, 0.6), label='Random guessing (area=0.5)')
plt.plot([0, 0, 1], [0, 1, 1], linestyle=':', color='black', label='Perfect performance (area=1.0)')
# Ustawienia osi i legendy
plt.xlim([-0.05, 1.05])
plt.ylim([-0.05, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.legend(loc='lower right')
plt.tight_layout()
plt.show()
# Wygenerowanie krzywej uczenia
train_sizes, train_scores, test_scores = learning_curve(estimator=pipe_dt,
X=X_train,
y=y_train,
train_sizes=np.linspace(0.1, 1.0, 10),
cv=10,
n_jobs=1)
# Obliczenie średnich i odchyleń standardowych dokładności dla danych treningowych i testowych
train_mean = np.mean(train_scores, axis=1)
train_std = np.std(train_scores, axis=1)
test_mean = np.mean(test_scores, axis=1)
test_std = np.std(test_scores, axis=1)
# Wykreślenie krzywej uczenia
plt.plot(train_sizes, train_mean,
color='blue', marker='o',
markersize=5, label='Training accuracy')
plt.fill_between(train_sizes,
train_mean + train_std,
train_mean - train_std,
alpha=0.15, color='blue')
plt.plot(train_sizes, test_mean,
color='green', linestyle='--',
marker='s', markersize=5,
label='Validation accuracy')
plt.fill_between(train_sizes,
test_mean + test_std,
test_mean - test_std,
alpha=0.15, color='green')
plt.grid()
plt.xlabel('Number of training examples')
plt.ylabel('Accuracy')
plt.legend(loc='lower right')
plt.ylim([0.8, 1.05])
plt.show()
pipe_dt = DecisionTreeClassifier(random_state = 1)
# Zdefiniuj zakres parametru max_depth do testowania
param_range = np.arange(1, 21)
# Wygeneruj krzywą walidacji dla parametru max_depth w DecisionTreeClassifier
train_scores, test_scores = validation_curve(estimator=pipe_dt,
X=X_train,
y=y_train,
param_name='max_depth',
param_range=param_range,
cv=10)
# Oblicz średnie dokładności dla danych treningowych i testowych
train_mean = np.mean(train_scores, axis=1)
train_std = np.std(train_scores, axis=1)
test_mean = np.mean(test_scores, axis=1)
test_std = np.std(test_scores, axis=1)
# Wykreśl krzywą walidacji
plt.plot(param_range, train_mean,
color='blue', marker='o',
markersize=5, label='Training accuracy')
plt.fill_between(param_range, train_mean + train_std,
train_mean - train_std, alpha=0.15,
color='blue')
plt.plot(param_range, test_mean,
color='green', linestyle='--',
marker='s', markersize=5,
label='Validation accuracy')
plt.fill_between(param_range,
test_mean + test_std,
test_mean - test_std,
alpha=0.15, color='green')
plt.grid()
plt.legend(loc='lower right')
plt.xlabel('Parameter max_depth')
plt.ylabel('Accuracy')
plt.ylim([0.8, 1.05])
plt.title('Validation Curve for Decision Tree Classifier')
plt.show()
pipe_dt = make_pipeline(StandardScaler(), DecisionTreeClassifier(random_state = 1))
# Definicja siatki parametrów do przeszukania
param_grid = {
'decisiontreeclassifier__max_depth': [None, 1, 2, 3, 4, 5], # Przykładowe wartości dla parametru max_depth
'decisiontreeclassifier__min_samples_split': [2, 5, 10], # Przykładowe wartości dla parametru min_samples_split
'decisiontreeclassifier__min_samples_leaf': [1, 2, 3, 4, 5], # Przykładowe wartości dla parametru min_samples_leaf
'decisiontreeclassifier__criterion': ['gini', 'entropy'] # Wybór kryterium
}
# Utworzenie obiektu GridSearchCV
gs_dt = GridSearchCV(estimator=pipe_dt,
param_grid=param_grid,
scoring='accuracy', # Wybór metryki oceny
cv=5, # Liczba podziałów walidacji krzyżowej
n_jobs=-1) # Wykorzystanie wszystkich rdzeni procesora
# Uruchomienie procesu przeszukiwania siatki hiperparametrów
gs_dt.fit(X_train, y_train)
# Wyświetlenie najlepszych parametrów i wyników
print(gs_dt.best_score_)
print(gs_dt.best_params_)
0.9245368650569329
{'decisiontreeclassifier__criterion': 'gini', 'decisiontreeclassifier__max_depth': 1, 'decisiontreeclassifier__min_samples_leaf': 1, 'decisiontreeclassifier__min_samples_split': 2}
clf_dt = gs_dt.best_estimator_
clf_dt.fit(X_train, y_train)
print(f'Test accuracy: {clf_dt.score(X_test, y_test):.3f}')
Test accuracy: 0.927
scorer = make_scorer(f1_score, pos_label = 0)
gs = GridSearchCV(estimator = pipe_dt,
param_grid = param_grid,
scoring = scorer,
cv = 2)
gs = gs.fit(X_train, y_train)
print(gs.best_score_)
print(gs.best_params_)
0.9142075721158038
{'decisiontreeclassifier__criterion': 'gini', 'decisiontreeclassifier__max_depth': 1, 'decisiontreeclassifier__min_samples_leaf': 1, 'decisiontreeclassifier__min_samples_split': 2}
nested_gs_dt = GridSearchCV(estimator = pipe_dt,
param_grid = param_grid,
scoring = 'accuracy',
cv = 2)
nested_scores_dt = cross_val_score(nested_gs_dt, X_train, y_train,
scoring = 'accuracy', cv = 5)
print(f'CV accuracy: {np.mean(nested_scores_dt):.3f}'
f' +/- {np.std(nested_scores_dt):.3f}')
CV accuracy: 0.925 +/- 0.006
# Definicja przestrzeni parametrów do przeszukania
param_dist = {
'decisiontreeclassifier__max_depth': randint(1, 20), # Przykładowe wartości dla parametru max_depth
'decisiontreeclassifier__min_samples_split': randint(2, 50), # Przykładowe wartości dla parametru min_samples_split
'decisiontreeclassifier__min_samples_leaf': randint(1, 20), # Przykładowe wartości dla parametru min_samples_leaf
'decisiontreeclassifier__criterion': ['gini', 'entropy'] # Wybór kryterium
}
# Inicjalizacja RandomizedSearchCV
rs_dt = RandomizedSearchCV(
estimator=pipe_dt,
param_distributions=param_dist,
scoring='accuracy',
cv=5,
n_iter=20,
n_jobs=-1,
random_state=42
)
# Dopasowanie modelu
rs_dt.fit(X_train, y_train)
# Wyświetlenie najlepszego wyniku i najlepszych parametrów
print(rs_dt.best_score_)
print(rs_dt.best_params_)
0.9255226251043096
{'decisiontreeclassifier__criterion': 'entropy', 'decisiontreeclassifier__max_depth': 4, 'decisiontreeclassifier__min_samples_leaf': 14, 'decisiontreeclassifier__min_samples_split': 32}
knn = KNeighborsClassifier(n_neighbors=5, p=2,
metric='minkowski')
knn.fit(X_train_pca, y_train)
plot_decision_regions(X_train_pca, y_train,
classifier=knn)
plt.xlabel('PC 1')
plt.ylabel('PC 2')
plt.legend(loc='upper left')
plt.tight_layout()
plt.show()
plot_decision_regions(X_test_pca, y_test, classifier=knn)
plt.xlabel('PC 1')
plt.ylabel('PC 2')
plt.legend(loc='best')
plt.tight_layout()
plt.show()
pipe_knn = make_pipeline(StandardScaler(),
KNeighborsClassifier(n_neighbors=5,
p=2,
metric='minkowski'))
pipe_knn.fit(X_train, y_train)
y_pred = pipe_knn.predict(X_test)
test_acc_knn = pipe_knn.score(X_test, y_test)
print(f'Test accuracy: {test_acc_knn: .3f}')
Test accuracy: 0.919
pipe_knn.fit(X_train, y_train)
y_pred = pipe_knn.predict(X_test)
confmat = confusion_matrix(y_true = y_test, y_pred = y_pred)
print(confmat)
[[297 29] [ 33 403]]
fig, ax = plt.subplots(figsize = (2.5, 2.5))
ax.matshow(confmat, cmap = plt.cm.Blues, alpha = 0.3)
for i in range(confmat.shape[0]):
for j in range(confmat.shape[1]):
ax.text(x = j, y = i, s = confmat[i, j],
va = 'center', ha = 'center')
ax.xaxis.set_ticks_position('bottom')
plt.xlabel('Predicted label')
plt.ylabel('True label')
plt.show()
scores_knn = cross_val_score(estimator = pipe_knn,
X = X_train,
y = y_train,
cv = 10,
n_jobs = 1)
print(f'CV accuracy scores: {scores_knn}')
print(f'CV accuracy scores: {np.mean(scores_knn):.3f}'
f' +/- {np.std(scores_knn):.3f}')
CV accuracy scores: [0.92459016 0.90491803 0.90819672 0.94098361 0.91803279 0.94098361 0.92786885 0.90491803 0.92434211 0.90789474] CV accuracy scores: 0.920 +/- 0.013
pre_val_knn = precision_score(y_true = y_test, y_pred = y_pred)
print(f'Precision: {pre_val_knn}')
rec_val_knn = recall_score(y_true = y_test, y_pred = y_pred)
print(f'Recall: {rec_val_knn}')
f1_val_knn = f1_score(y_true = y_test, y_pred = y_pred)
print(f'F1: {f1_val_knn}')
mcc_val_knn = matthews_corrcoef(y_true = y_test, y_pred = y_pred)
print(f'MCC: {mcc_val_knn:.3f}')
Precision: 0.9328703703703703 Recall: 0.9243119266055045 F1: 0.9285714285714285 MCC: 0.834
# Tworzenie potoku z użyciem KNeighborsClassifier i StandardScaler
pipe_knn = make_pipeline(StandardScaler(), KNeighborsClassifier(n_neighbors=5,
p=2,
metric='minkowski'))
# Podział danych do walidacji krzyżowej
cv = list(StratifiedKFold(n_splits=3).split(X_train, y_train))
# Inicjalizacja wykresu
fig = plt.figure(figsize=(7, 5))
mean_fpr = np.linspace(0, 1, 100)
all_tpr = []
# Dla każdego podziału walidacji krzyżowej
for i, (train, test) in enumerate(cv):
# Dopasowanie modelu do danych treningowych
probas = pipe_knn.fit(X_train[train], y_train[train]).predict_proba(X_train[test])
# Obliczenie współczynników True Positive Rate (TPR) oraz False Positive Rate (FPR)
fpr, tpr, thresholds = roc_curve(y_train[test], probas[:, 1], pos_label=1)
# Interpolacja wyników na średnią krzywą ROC
mean_tpr = np.interp(mean_fpr, fpr, tpr)
mean_tpr[0] = 0.0
all_tpr.append(mean_tpr)
# Obliczenie pola pod krzywą ROC (AUC)
roc_auc = auc(fpr, tpr)
# Wyświetlenie krzywej ROC dla każdego podziału
plt.plot(fpr, tpr, label=f'ROC fold {i+1} (area = {roc_auc:.2f})')
# Obliczenie średniego True Positive Rate
mean_tpr = np.mean(all_tpr, axis=0)
mean_tpr[-1] = 1.0
# Obliczenie średniego pola pod krzywą ROC (AUC)
mean_auc = auc(mean_fpr, mean_tpr)
# Wyświetlenie średniej krzywej ROC
plt.plot(mean_fpr, mean_tpr, 'k--', label=f'Mean ROC (area = {mean_auc:.2f})', lw=2)
# Wyświetlenie linii referencyjnych
plt.plot([0, 1], [0, 1], linestyle='--', color=(0.6, 0.6, 0.6), label='Random guessing (area=0.5)')
plt.plot([0, 0, 1], [0, 1, 1], linestyle=':', color='black', label='Perfect performance (area=1.0)')
# Ustawienia osi i legendy
plt.xlim([-0.05, 1.05])
plt.ylim([-0.05, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.legend(loc='lower right')
plt.tight_layout()
plt.show()
# Wygenerowanie krzywej uczenia
train_sizes, train_scores, test_scores = learning_curve(estimator=pipe_knn,
X=X_train,
y=y_train,
train_sizes=np.linspace(0.1, 1.0, 10),
cv=10,
n_jobs=1)
# Obliczenie średnich i odchyleń standardowych dokładności dla danych treningowych i testowych
train_mean = np.mean(train_scores, axis=1)
train_std = np.std(train_scores, axis=1)
test_mean = np.mean(test_scores, axis=1)
test_std = np.std(test_scores, axis=1)
# Wykreślenie krzywej uczenia
plt.plot(train_sizes, train_mean,
color='blue', marker='o',
markersize=5, label='Training accuracy')
plt.fill_between(train_sizes,
train_mean + train_std,
train_mean - train_std,
alpha=0.15, color='blue')
plt.plot(train_sizes, test_mean,
color='green', linestyle='--',
marker='s', markersize=5,
label='Validation accuracy')
plt.fill_between(train_sizes,
test_mean + test_std,
test_mean - test_std,
alpha=0.15, color='green')
plt.grid()
plt.xlabel('Number of training examples')
plt.ylabel('Accuracy')
plt.legend(loc='lower right')
plt.ylim([0.8, 1.05])
plt.show()
pipe_knn = KNeighborsClassifier()
# Zdefiniuj zakres parametru n_neighbors do testowania
param_range = range(1, 11)
# Wygeneruj krzywą walidacji dla parametru n_neighbors w KNeighborsClassifier
train_scores, test_scores = validation_curve(estimator=pipe_knn,
X=X_train,
y=y_train,
param_name='n_neighbors',
param_range=param_range,
cv=10)
# Oblicz średnie dokładności dla danych treningowych i testowych
train_mean = np.mean(train_scores, axis=1)
train_std = np.std(train_scores, axis=1)
test_mean = np.mean(test_scores, axis=1)
test_std = np.std(test_scores, axis=1)
# Wykreśl krzywą walidacji
plt.plot(param_range, train_mean,
color='blue', marker='o',
markersize=5, label='Training accuracy')
plt.fill_between(param_range, train_mean + train_std,
train_mean - train_std, alpha=0.15,
color='blue')
plt.plot(param_range, test_mean,
color='green', linestyle='--',
marker='s', markersize=5,
label='Validation accuracy')
plt.fill_between(param_range,
test_mean + test_std,
test_mean - test_std,
alpha=0.15, color='green')
plt.grid()
plt.legend(loc='lower right')
plt.xlabel('Parameter n_neighbors')
plt.ylabel('Accuracy')
plt.ylim([0.8, 1.05])
plt.title('Validation Curve for KNN Classifier')
plt.show()
# Utworzenie potoku zawierającego StandardScaler i KNeighborsClassifier
pipe_knn = make_pipeline(StandardScaler(), KNeighborsClassifier())
# Definicja siatki parametrów do przeszukania
param_grid = {
'kneighborsclassifier__n_neighbors': [3, 5, 7, 9, 11], # Przykładowe wartości dla parametru n_neighbors
'kneighborsclassifier__metric': ['euclidean', 'manhattan', 'minkowski'], # Przykładowe wartości dla parametru metric
}
# Utworzenie obiektu GridSearchCV
gs_knn = GridSearchCV(estimator=pipe_knn,
param_grid=param_grid,
scoring='accuracy', # Wybór metryki oceny
cv=5, # Liczba podziałów walidacji krzyżowej
n_jobs=-1) # Wykorzystanie wszystkich rdzeni procesora
# Uruchomienie procesu przeszukiwania siatki hiperparametrów
gs_knn.fit(X_train, y_train)
# Wyświetlenie najlepszych parametrów i wyników
print(gs_knn.best_score_)
print(gs_knn.best_params_)
0.9258494172117688
{'kneighborsclassifier__metric': 'euclidean', 'kneighborsclassifier__n_neighbors': 11}
clf_knn = gs_knn.best_estimator_
clf_knn.fit(X_train, y_train)
print(f'Test accuracy: {clf_knn.score(X_test, y_test):.3f}')
Test accuracy: 0.920
scorer = make_scorer(f1_score, pos_label = 0)
gs = GridSearchCV(estimator = pipe_knn,
param_grid = param_grid,
scoring = scorer,
cv = 2)
gs = gs.fit(X_train, y_train)
print(gs.best_score_)
print(gs.best_params_)
0.9160892994611238
{'kneighborsclassifier__metric': 'euclidean', 'kneighborsclassifier__n_neighbors': 11}
nested_gs_knn = GridSearchCV(estimator = pipe_knn,
param_grid = param_grid,
scoring = 'accuracy',
cv = 2)
nested_scores_knn = cross_val_score(nested_gs_knn, X_train, y_train,
scoring = 'accuracy', cv = 5)
print(f'CV accuracy: {np.mean(nested_scores_knn):.3f}'
f' +/- {np.std(nested_scores_knn):.3f}')
CV accuracy: 0.924 +/- 0.007
# Definicja przestrzeni parametrów do przeszukania
param_dist = {
'kneighborsclassifier__n_neighbors': randint(1, 20), # Przykładowe wartości dla parametru n_neighbors
'kneighborsclassifier__metric': ['euclidean', 'manhattan', 'minkowski'], # Przykładowe wartości dla parametru metric
}
# Inicjalizacja RandomizedSearchCV
rs_knn = RandomizedSearchCV(
estimator=pipe_knn,
param_distributions=param_dist,
scoring='accuracy',
cv=5,
n_iter=20,
n_jobs=-1,
random_state=42
)
# Dopasowanie modelu
rs_knn.fit(X_train, y_train)
# Wyświetlenie najlepszego wyniku i najlepszych parametrów
print(rs_knn.best_score_)
print(rs_knn.best_params_)
0.9258494172117688
{'kneighborsclassifier__metric': 'minkowski', 'kneighborsclassifier__n_neighbors': 11}
# Inicjalizacja lasu losowego
forest = RandomForestClassifier(n_estimators=100, random_state=1)
forest.fit(X_train_pca, y_train)
# Wygenerowanie wizualizacji granic decyzyjnych
plot_decision_regions(X_train_pca, y_train, classifier=forest)
plt.xlabel('PC 1')
plt.ylabel('PC 2')
plt.legend(loc='upper left')
plt.tight_layout()
plt.show()
plot_decision_regions(X_test_pca, y_test, classifier=forest)
plt.xlabel('PC 1')
plt.ylabel('PC 2')
plt.legend(loc='best')
plt.tight_layout()
plt.show()
pipe_forest = make_pipeline(StandardScaler(),
RandomForestClassifier(n_estimators=100,
random_state=1))
pipe_forest.fit(X_train, y_train)
y_pred = pipe_forest.predict(X_test)
test_acc_forest = pipe_forest.score(X_test, y_test)
print(f'Test accuracy: {test_acc_forest: .3f}')
Test accuracy: 0.925
pipe_forest.fit(X_train, y_train)
y_pred = pipe_forest.predict(X_test)
confmat = confusion_matrix(y_true = y_test, y_pred = y_pred)
print(confmat)
[[298 28] [ 29 407]]
fig, ax = plt.subplots(figsize = (2.5, 2.5))
ax.matshow(confmat, cmap = plt.cm.Blues, alpha = 0.3)
for i in range(confmat.shape[0]):
for j in range(confmat.shape[1]):
ax.text(x = j, y = i, s = confmat[i, j],
va = 'center', ha = 'center')
ax.xaxis.set_ticks_position('bottom')
plt.xlabel('Predicted label')
plt.ylabel('True label')
plt.show()
scores_forest = cross_val_score(estimator = pipe_forest,
X = X_train,
y = y_train,
cv = 10,
n_jobs = 1)
print(f'CV accuracy scores: {scores_forest}')
print(f'CV accuracy scores: {np.mean(scores_forest):.3f}'
f' +/- {np.std(scores_forest):.3f}')
CV accuracy scores: [0.93114754 0.92786885 0.90491803 0.92459016 0.92459016 0.95409836 0.90163934 0.91803279 0.91447368 0.90789474] CV accuracy scores: 0.921 +/- 0.015
pre_val_forest = precision_score(y_true = y_test, y_pred = y_pred)
print(f'Precision: {pre_val_forest}')
rec_val_forest = recall_score(y_true = y_test, y_pred = y_pred)
print(f'Recall: {rec_val_forest}')
f1_val_forest = f1_score(y_true = y_test, y_pred = y_pred)
print(f'F1: {f1_val_forest}')
mcc_val_forest = matthews_corrcoef(y_true = y_test, y_pred = y_pred)
print(f'MCC: {mcc_val_forest:.3f}')
Precision: 0.9356321839080459 Recall: 0.9334862385321101 F1: 0.9345579793340987 MCC: 0.847
# Podział danych do walidacji krzyżowej
cv = list(StratifiedKFold(n_splits=3).split(X_train, y_train))
# Inicjalizacja wykresu
fig = plt.figure(figsize=(7, 5))
mean_fpr = np.linspace(0, 1, 100)
all_tpr = []
# Dla każdego podziału walidacji krzyżowej
for i, (train, test) in enumerate(cv):
# Dopasowanie modelu do danych treningowych
probas = pipe_forest.fit(X_train[train], y_train[train]).predict_proba(X_train[test])
# Obliczenie współczynników True Positive Rate (TPR) oraz False Positive Rate (FPR)
fpr, tpr, thresholds = roc_curve(y_train[test], probas[:, 1], pos_label=1)
# Interpolacja wyników na średnią krzywą ROC
mean_tpr = np.interp(mean_fpr, fpr, tpr)
mean_tpr[0] = 0.0
all_tpr.append(mean_tpr)
# Obliczenie pola pod krzywą ROC (AUC)
roc_auc = auc(fpr, tpr)
# Wyświetlenie krzywej ROC dla każdego podziału
plt.plot(fpr, tpr, label=f'ROC fold {i+1} (area = {roc_auc:.2f})')
# Obliczenie średniego True Positive Rate
mean_tpr = np.mean(all_tpr, axis=0)
mean_tpr[-1] = 1.0
# Obliczenie średniego pola pod krzywą ROC (AUC)
mean_auc = auc(mean_fpr, mean_tpr)
# Wyświetlenie średniej krzywej ROC
plt.plot(mean_fpr, mean_tpr, 'k--', label=f'Mean ROC (area = {mean_auc:.2f})', lw=2)
# Wyświetlenie linii referencyjnych
plt.plot([0, 1], [0, 1], linestyle='--', color=(0.6, 0.6, 0.6), label='Random guessing (area=0.5)')
plt.plot([0, 0, 1], [0, 1, 1], linestyle=':', color='black', label='Perfect performance (area=1.0)')
# Ustawienia osi i legendy
plt.xlim([-0.05, 1.05])
plt.ylim([-0.05, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.legend(loc='lower right')
plt.tight_layout()
plt.show()
# Wygenerowanie krzywej uczenia
train_sizes, train_scores, test_scores = learning_curve(estimator=pipe_forest,
X=X_train,
y=y_train,
train_sizes=np.linspace(0.1, 1.0, 10),
cv=10,
n_jobs=1)
# Obliczenie średnich i odchyleń standardowych dokładności dla danych treningowych i testowych
train_mean = np.mean(train_scores, axis=1)
train_std = np.std(train_scores, axis=1)
test_mean = np.mean(test_scores, axis=1)
test_std = np.std(test_scores, axis=1)
# Wykreślenie krzywej uczenia
plt.plot(train_sizes, train_mean,
color='blue', marker='o',
markersize=5, label='Training accuracy')
plt.fill_between(train_sizes,
train_mean + train_std,
train_mean - train_std,
alpha=0.15, color='blue')
plt.plot(train_sizes, test_mean,
color='green', linestyle='--',
marker='s', markersize=5,
label='Validation accuracy')
plt.fill_between(train_sizes,
test_mean + test_std,
test_mean - test_std,
alpha=0.15, color='green')
plt.grid()
plt.xlabel('Number of training examples')
plt.ylabel('Accuracy')
plt.legend(loc='lower right')
plt.ylim([0.8, 1.05])
plt.show()
pipe_forest = RandomForestClassifier(random_state=1)
# Zdefiniowanie zakresu parametru n_estimators do testowania
param_range = [10, 50, 100, 200]
# Wygenerowanie krzywej walidacji dla parametru n_estimators w RandomForestClassifier
train_scores, test_scores = validation_curve(estimator=pipe_forest,
X=X_train,
y=y_train,
param_name='n_estimators',
param_range=param_range,
cv=10)
# Obliczenie średnich dokładności dla danych treningowych i testowych
train_mean = np.mean(train_scores, axis=1)
train_std = np.std(train_scores, axis=1)
test_mean = np.mean(test_scores, axis=1)
test_std = np.std(test_scores, axis=1)
# Wykreślenie krzywej walidacji
plt.plot(param_range, train_mean,
color='blue', marker='o',
markersize=5, label='Training accuracy')
plt.fill_between(param_range, train_mean + train_std,
train_mean - train_std, alpha=0.15,
color='blue')
plt.plot(param_range, test_mean,
color='green', linestyle='--',
marker='s', markersize=5,
label='Validation accuracy')
plt.fill_between(param_range,
test_mean + test_std,
test_mean - test_std,
alpha=0.15, color='green')
plt.grid()
plt.legend(loc='lower right')
plt.xlabel('Parameter n_estimators')
plt.ylabel('Accuracy')
plt.ylim([0.8, 1.05])
plt.title('Validation Curve for RandomForestClassifier')
plt.show()
# Utworzenie potoku zawierającego StandardScaler i RandomForestClassifier
pipe_forest = make_pipeline(StandardScaler(), RandomForestClassifier(random_state=1))
# Definicja siatki parametrów do przeszukania
param_grid = {
'randomforestclassifier__n_estimators': [50, 100, 150], # Liczba estymatorów
'randomforestclassifier__max_depth': [None, 5, 10, 15], # Maksymalna głębokość drzewa
'randomforestclassifier__bootstrap': [True, False] # Czy stosować bootstrap podczas budowy drzew
}
# Utworzenie obiektu GridSearchCV
gs_forest = GridSearchCV(estimator=pipe_forest,
param_grid=param_grid,
scoring='accuracy', # Wybór metryki oceny
cv=5, # Liczba podziałów walidacji krzyżowej
n_jobs=-1) # Wykorzystanie wszystkich rdzeni procesora
# Uruchomienie procesu przeszukiwania siatki hiperparametrów
gs_forest.fit(X_train, y_train)
# Wyświetlenie najlepszych parametrów i wyników
print(gs_forest.best_score_)
print(gs_forest.best_params_)
0.927159815876605
{'randomforestclassifier__bootstrap': False, 'randomforestclassifier__max_depth': 5, 'randomforestclassifier__n_estimators': 50}
clf_forest = gs_forest.best_estimator_
clf_forest.fit(X_train, y_train)
print(f'Test accuracy: {clf_forest.score(X_test, y_test):.3f}')
Test accuracy: 0.928
scorer = make_scorer(f1_score, pos_label = 0)
gs = GridSearchCV(estimator = pipe_forest,
param_grid = param_grid,
scoring = scorer,
cv = 2)
gs = gs.fit(X_train, y_train)
print(gs.best_score_)
print(gs.best_params_)
0.9130744027489555
{'randomforestclassifier__bootstrap': True, 'randomforestclassifier__max_depth': 5, 'randomforestclassifier__n_estimators': 100}
nested_gs_forest = GridSearchCV(estimator = pipe_forest,
param_grid = param_grid,
scoring = 'accuracy',
cv = 2)
nested_scores_forest = cross_val_score(nested_gs_forest, X_train, y_train,
scoring = 'accuracy', cv = 5)
print(f'CV accuracy: {np.mean(nested_scores_forest):.3f}'
f' +/- {np.std(nested_scores_forest):.3f}')
CV accuracy: 0.924 +/- 0.010
# Definicja przestrzeni parametrów do przeszukania
param_dist = {
'randomforestclassifier__n_estimators': randint(100, 1000), # Liczba estymatorów
'randomforestclassifier__max_depth': [None, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100], # Maksymalna głębokość drzewa
'randomforestclassifier__min_samples_split': randint(2, 20), # Minimalna liczba próbek wymagana do podziału węzła
'randomforestclassifier__min_samples_leaf': randint(1, 20), # Minimalna liczba próbek wymagana w liściu węzła
'randomforestclassifier__bootstrap': [True, False] # Czy stosować bootstrap podczas budowy drzew
}
# Inicjalizacja RandomizedSearchCV
rs_forest = RandomizedSearchCV(
estimator=pipe_forest,
param_distributions=param_dist,
scoring='accuracy',
cv=5,
n_iter=20,
n_jobs=-1,
random_state=42
)
# Dopasowanie modelu
rs_forest.fit(X_train, y_train)
# Wyświetlenie najlepszego wyniku i najlepszych parametrów
print(rs_forest.best_score_)
print(rs_forest.best_params_)
0.9284718296589409
{'randomforestclassifier__bootstrap': True, 'randomforestclassifier__max_depth': 30, 'randomforestclassifier__min_samples_leaf': 15, 'randomforestclassifier__min_samples_split': 12, 'randomforestclassifier__n_estimators': 171}
# Inicjalizacja klasyfikatora MLP
mlp = MLPClassifier(hidden_layer_sizes=(100, 100), max_iter=1000, random_state=1)
# Dopasowanie klasyfikatora do danych
mlp.fit(X_train_pca, y_train)
# Wizualizacja granic decyzyjnych
plot_decision_regions(X_train_pca, y_train, classifier=mlp)
plt.xlabel('PC 1')
plt.ylabel('PC 2')
plt.title('Decision Boundary for MLP')
plt.show()
plot_decision_regions(X_test_pca, y_test, classifier=mlp)
plt.xlabel('PC 1')
plt.ylabel('PC 2')
plt.legend(loc='best')
plt.tight_layout()
plt.show()
pipe_mlp = make_pipeline(StandardScaler(),
MLPClassifier(hidden_layer_sizes=(100, 100),
max_iter=1000,
random_state=1))
pipe_mlp.fit(X_train, y_train)
y_pred = pipe_mlp.predict(X_test)
test_acc_mlp = pipe_mlp.score(X_test, y_test)
print(f'Test accuracy: {test_acc_mlp: .3f}')
Test accuracy: 0.925
pipe_mlp.fit(X_train, y_train)
y_pred = pipe_mlp.predict(X_test)
confmat = confusion_matrix(y_true = y_test, y_pred = y_pred)
print(confmat)
[[300 26] [ 31 405]]
fig, ax = plt.subplots(figsize = (2.5, 2.5))
ax.matshow(confmat, cmap = plt.cm.Blues, alpha = 0.3)
for i in range(confmat.shape[0]):
for j in range(confmat.shape[1]):
ax.text(x = j, y = i, s = confmat[i, j],
va = 'center', ha = 'center')
ax.xaxis.set_ticks_position('bottom')
plt.xlabel('Predicted label')
plt.ylabel('True label')
plt.show()
scores_mlp = cross_val_score(estimator = pipe_mlp,
X = X_train,
y = y_train,
cv = 10,
n_jobs = 1)
print(f'CV accuracy scores: {scores_mlp}')
print(f'CV accuracy scores: {np.mean(scores_mlp):.3f}'
f' +/- {np.std(scores_mlp):.3f}')
CV accuracy scores: [0.93770492 0.93114754 0.91803279 0.94754098 0.92459016 0.95737705 0.92786885 0.90491803 0.91776316 0.91447368] CV accuracy scores: 0.928 +/- 0.015
pre_val_mlp = precision_score(y_true = y_test, y_pred = y_pred)
print(f'Precision: {pre_val_mlp}')
rec_val_mlp = recall_score(y_true = y_test, y_pred = y_pred)
print(f'Recall: {rec_val_mlp}')
f1_val_mlp = f1_score(y_true = y_test, y_pred = y_pred)
print(f'F1: {f1_val_mlp}')
mcc_val_mlp = matthews_corrcoef(y_true = y_test, y_pred = y_pred)
print(f'MCC: {mcc_val_mlp:.3f}')
Precision: 0.9396751740139211 Recall: 0.9288990825688074 F1: 0.9342560553633218 MCC: 0.848
# Podział danych do walidacji krzyżowej
cv = list(StratifiedKFold(n_splits=3).split(X_train, y_train))
# Inicjalizacja wykresu
fig = plt.figure(figsize=(7, 5))
mean_fpr = np.linspace(0, 1, 100)
all_tpr = []
# Dla każdego podziału walidacji krzyżowej
for i, (train, test) in enumerate(cv):
# Dopasowanie modelu do danych treningowych
probas = pipe_mlp.fit(X_train[train], y_train[train]).predict_proba(X_train[test])
# Obliczenie współczynników True Positive Rate (TPR) oraz False Positive Rate (FPR)
fpr, tpr, thresholds = roc_curve(y_train[test], probas[:, 1], pos_label=1)
# Interpolacja wyników na średnią krzywą ROC
mean_tpr = np.interp(mean_fpr, fpr, tpr)
mean_tpr[0] = 0.0
all_tpr.append(mean_tpr)
# Obliczenie pola pod krzywą ROC (AUC)
roc_auc = auc(fpr, tpr)
# Wyświetlenie krzywej ROC dla każdego podziału
plt.plot(fpr, tpr, label=f'ROC fold {i+1} (area = {roc_auc:.2f})')
# Obliczenie średniego True Positive Rate
mean_tpr = np.mean(all_tpr, axis=0)
mean_tpr[-1] = 1.0
# Obliczenie średniego pola pod krzywą ROC (AUC)
mean_auc = auc(mean_fpr, mean_tpr)
# Wyświetlenie średniej krzywej ROC
plt.plot(mean_fpr, mean_tpr, 'k--', label=f'Mean ROC (area = {mean_auc:.2f})', lw=2)
# Wyświetlenie linii referencyjnych
plt.plot([0, 1], [0, 1], linestyle='--', color=(0.6, 0.6, 0.6), label='Random guessing (area=0.5)')
plt.plot([0, 0, 1], [0, 1, 1], linestyle=':', color='black', label='Perfect performance (area=1.0)')
# Ustawienia osi i legendy
plt.xlim([-0.05, 1.05])
plt.ylim([-0.05, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.legend(loc='lower right')
plt.tight_layout()
plt.show()
# Wygenerowanie krzywej uczenia
train_sizes, train_scores, test_scores = learning_curve(estimator=pipe_mlp,
X=X_train,
y=y_train,
train_sizes=np.linspace(0.1, 1.0, 10),
cv=10,
n_jobs=1)
# Obliczenie średnich i odchyleń standardowych dokładności dla danych treningowych i testowych
train_mean = np.mean(train_scores, axis=1)
train_std = np.std(train_scores, axis=1)
test_mean = np.mean(test_scores, axis=1)
test_std = np.std(test_scores, axis=1)
# Wykreślenie krzywej uczenia
plt.plot(train_sizes, train_mean,
color='blue', marker='o',
markersize=5, label='Training accuracy')
plt.fill_between(train_sizes,
train_mean + train_std,
train_mean - train_std,
alpha=0.15, color='blue')
plt.plot(train_sizes, test_mean,
color='green', linestyle='--',
marker='s', markersize=5,
label='Validation accuracy')
plt.fill_between(train_sizes,
test_mean + test_std,
test_mean - test_std,
alpha=0.15, color='green')
plt.grid()
plt.xlabel('Number of training examples')
plt.ylabel('Accuracy')
plt.legend(loc='lower right')
plt.ylim([0.8, 1.05])
plt.show()
# Utwórz potok zawierający StandardScaler i MLPClassifier
pipe_mlp = make_pipeline(StandardScaler(), MLPClassifier(random_state=1, max_iter=1000))
# Zdefiniuj zakres parametru alpha do testowania
param_range_alpha = [0.0001, 0.001, 0.01, 0.1, 1.0, 10.0]
# Wygeneruj krzywą walidacji dla parametru alpha w MLPClassifier
train_scores, test_scores = validation_curve(estimator=pipe_mlp,
X=X_train,
y=y_train,
param_name='mlpclassifier__alpha',
param_range=param_range_alpha,
cv=10)
# Oblicz średnie dokładności dla danych treningowych i testowych
train_mean = np.mean(train_scores, axis=1)
train_std = np.std(train_scores, axis=1)
test_mean = np.mean(test_scores, axis=1)
test_std = np.std(test_scores, axis=1)
# Wykreśl krzywą walidacji
plt.plot(param_range_alpha, train_mean,
color='blue', marker='o',
markersize=5, label='Training accuracy')
plt.fill_between(param_range_alpha, train_mean + train_std,
train_mean - train_std, alpha=0.15,
color='blue')
plt.plot(param_range_alpha, test_mean,
color='green', linestyle='--',
marker='s', markersize=5,
label='Validation accuracy')
plt.fill_between(param_range_alpha,
test_mean + test_std,
test_mean - test_std,
alpha=0.15, color='green')
plt.grid()
plt.xscale('log')
plt.legend(loc='lower right')
plt.xlabel('Parameter alpha')
plt.ylabel('Accuracy')
plt.ylim([0.8, 1.05])
plt.title('Validation Curve for MLPClassifier')
plt.show()
# Definicja siatki parametrów do przeszukania
param_grid = {
'mlpclassifier__hidden_layer_sizes': [(50,), (100,), (50, 50), (100, 100)], # Przykładowe konfiguracje warstw ukrytych
'mlpclassifier__activation': ['logistic', 'relu'], # Funkcje aktywacji
'mlpclassifier__alpha': [0.0001, 0.001, 0.01], # Parametr regularyzacji
}
# Utworzenie obiektu GridSearchCV
gs_mlp = GridSearchCV(estimator=pipe_mlp,
param_grid=param_grid,
scoring='accuracy', # Wybór metryki oceny
cv=5, # Liczba podziałów walidacji krzyżowej
n_jobs=-1) # Wykorzystanie wszystkich rdzeni procesora
# Uruchomienie procesu przeszukiwania siatki hiperparametrów
gs_mlp.fit(X_train, y_train)
# Wyświetlenie najlepszych parametrów i wyników
print(gs_mlp.best_score_)
print(gs_mlp.best_params_)
0.9294575897063178
{'mlpclassifier__activation': 'logistic', 'mlpclassifier__alpha': 0.01, 'mlpclassifier__hidden_layer_sizes': (100, 100)}
clf_mlp = gs_mlp.best_estimator_
clf_mlp.fit(X_train, y_train)
print(f'Test accuracy: {clf_mlp.score(X_test, y_test):.3f}')
Test accuracy: 0.920
scorer = make_scorer(f1_score, pos_label = 0)
gs = GridSearchCV(estimator = pipe_mlp,
param_grid = param_grid,
scoring = scorer,
cv = 2)
gs = gs.fit(X_train, y_train)
print(gs.best_score_)
print(gs.best_params_)
0.9172959662288931
{'mlpclassifier__activation': 'logistic', 'mlpclassifier__alpha': 0.0001, 'mlpclassifier__hidden_layer_sizes': (100, 100)}
nested_gs_mlp = GridSearchCV(estimator = pipe_mlp,
param_grid = param_grid,
scoring = 'accuracy',
cv = 2)
nested_scores_mlp = cross_val_score(nested_gs_mlp, X_train, y_train,
scoring = 'accuracy', cv = 5)
print(f'CV accuracy: {np.mean(nested_scores_mlp):.3f}'
f' +/- {np.std(nested_scores_mlp):.3f}')
CV accuracy: 0.928 +/- 0.012
# Utworzenie potoku z MLPClassifier
pipe_mlp = MLPClassifier()
# Definicja przestrzeni parametrów do przeszukania
param_dist = {
'hidden_layer_sizes': [(50,), (100,), (50, 50), (100, 100)], # Przykładowe konfiguracje warstw ukrytych
'activation': ['logistic', 'relu'], # Funkcje aktywacji
'alpha': [0.0001, 0.001, 0.01], # Parametr regularyzacji
}
# Inicjalizacja RandomizedSearchCV
rs_mlp = RandomizedSearchCV(
estimator=pipe_mlp,
param_distributions=param_dist,
scoring='accuracy',
cv=5,
n_iter=20,
n_jobs=-1,
random_state=42
)
# Dopasowanie modelu
rs_mlp.fit(X_train, y_train)
# Wyświetlenie najlepszego wyniku i najlepszych parametrów
print(rs_mlp.best_score_)
print(rs_mlp.best_params_)
c:\Users\Dawid\anaconda3\Lib\site-packages\joblib\externals\loky\process_executor.py:700: UserWarning: A worker stopped while some jobs were given to the executor. This can be caused by a too short worker timeout or by a memory leak. warnings.warn(
0.691569086651054
{'hidden_layer_sizes': (100,), 'alpha': 0.001, 'activation': 'relu'}
# Inicjalizacja klasyfikatora LDA
lda = LDA()
# Dopasowanie klasyfikatora do danych
lda.fit(X_train_pca, y_train)
# Wizualizacja granic decyzyjnych
plot_decision_regions(X_train_pca, y_train, classifier=lda)
plt.xlabel('PC 1')
plt.ylabel('PC 2')
plt.title('Decision Boundary for LDA')
plt.show()
plot_decision_regions(X_test_pca, y_test, classifier=lda)
plt.xlabel('PC 1')
plt.ylabel('PC 2')
plt.legend(loc='best')
plt.tight_layout()
plt.show()
pipe_lda = make_pipeline(StandardScaler(),
LDA())
pipe_lda.fit(X_train, y_train)
y_pred = pipe_lda.predict(X_test)
test_acc_lda = pipe_lda.score(X_test, y_test)
print(f'Test accuracy: {test_acc_lda: .3f}')
Test accuracy: 0.923
pipe_lda.fit(X_train, y_train)
y_pred = pipe_lda.predict(X_test)
confmat = confusion_matrix(y_true = y_test, y_pred = y_pred)
print(confmat)
[[291 35] [ 24 412]]
fig, ax = plt.subplots(figsize = (2.5, 2.5))
ax.matshow(confmat, cmap = plt.cm.Blues, alpha = 0.3)
for i in range(confmat.shape[0]):
for j in range(confmat.shape[1]):
ax.text(x = j, y = i, s = confmat[i, j],
va = 'center', ha = 'center')
ax.xaxis.set_ticks_position('bottom')
plt.xlabel('Predicted label')
plt.ylabel('True label')
plt.show()
scores_lda = cross_val_score(estimator = pipe_lda,
X = X_train,
y = y_train,
cv = 10,
n_jobs = 1)
print(f'CV accuracy scores: {scores_lda}')
print(f'CV accuracy scores: {np.mean(scores_lda):.3f}'
f' +/- {np.std(scores_lda):.3f}')
CV accuracy scores: [0.93770492 0.9442623 0.92459016 0.93442623 0.92786885 0.95737705 0.92786885 0.91147541 0.92763158 0.92434211] CV accuracy scores: 0.932 +/- 0.012
pre_val_lda = precision_score(y_true = y_test, y_pred = y_pred)
print(f'Precision: {pre_val_lda}')
rec_val_lda = recall_score(y_true = y_test, y_pred = y_pred)
print(f'Recall: {rec_val_lda}')
f1_val_lda = f1_score(y_true = y_test, y_pred = y_pred)
print(f'F1: {f1_val_lda}')
mcc_val_lda = matthews_corrcoef(y_true = y_test, y_pred = y_pred)
print(f'MCC: {mcc_val_lda:.3f}')
Precision: 0.9217002237136466 Recall: 0.944954128440367 F1: 0.9331823329558324 MCC: 0.842
# Podział danych do walidacji krzyżowej
cv = list(StratifiedKFold(n_splits=3).split(X_train, y_train))
# Inicjalizacja wykresu
fig = plt.figure(figsize=(7, 5))
mean_fpr = np.linspace(0, 1, 100)
all_tpr = []
# Dla każdego podziału walidacji krzyżowej
for i, (train, test) in enumerate(cv):
# Dopasowanie modelu do danych treningowych
probas = pipe_lda.fit(X_train[train], y_train[train]).predict_proba(X_train[test])
# Obliczenie współczynników True Positive Rate (TPR) oraz False Positive Rate (FPR)
fpr, tpr, thresholds = roc_curve(y_train[test], probas[:, 1], pos_label=1)
# Interpolacja wyników na średnią krzywą ROC
mean_tpr = np.interp(mean_fpr, fpr, tpr)
mean_tpr[0] = 0.0
all_tpr.append(mean_tpr)
# Obliczenie pola pod krzywą ROC (AUC)
roc_auc = auc(fpr, tpr)
# Wyświetlenie krzywej ROC dla każdego podziału
plt.plot(fpr, tpr, label=f'ROC fold {i+1} (area = {roc_auc:.2f})')
# Obliczenie średniego True Positive Rate
mean_tpr = np.mean(all_tpr, axis=0)
mean_tpr[-1] = 1.0
# Obliczenie średniego pola pod krzywą ROC (AUC)
mean_auc = auc(mean_fpr, mean_tpr)
# Wyświetlenie średniej krzywej ROC
plt.plot(mean_fpr, mean_tpr, 'k--', label=f'Mean ROC (area = {mean_auc:.2f})', lw=2)
# Wyświetlenie linii referencyjnych
plt.plot([0, 1], [0, 1], linestyle='--', color=(0.6, 0.6, 0.6), label='Random guessing (area=0.5)')
plt.plot([0, 0, 1], [0, 1, 1], linestyle=':', color='black', label='Perfect performance (area=1.0)')
# Ustawienia osi i legendy
plt.xlim([-0.05, 1.05])
plt.ylim([-0.05, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.legend(loc='lower right')
plt.tight_layout()
plt.show()
# Wygenerowanie krzywej uczenia
train_sizes, train_scores, test_scores = learning_curve(estimator=pipe_lda,
X=X_train,
y=y_train,
train_sizes=np.linspace(0.1, 1.0, 10),
cv=10,
n_jobs=1)
# Obliczenie średnich i odchyleń standardowych dokładności dla danych treningowych i testowych
train_mean = np.mean(train_scores, axis=1)
train_std = np.std(train_scores, axis=1)
test_mean = np.mean(test_scores, axis=1)
test_std = np.std(test_scores, axis=1)
# Wykreślenie krzywej uczenia
plt.plot(train_sizes, train_mean,
color='blue', marker='o',
markersize=5, label='Training accuracy')
plt.fill_between(train_sizes,
train_mean + train_std,
train_mean - train_std,
alpha=0.15, color='blue')
plt.plot(train_sizes, test_mean,
color='green', linestyle='--',
marker='s', markersize=5,
label='Validation accuracy')
plt.fill_between(train_sizes,
test_mean + test_std,
test_mean - test_std,
alpha=0.15, color='green')
plt.grid()
plt.xlabel('Number of training examples')
plt.ylabel('Accuracy')
plt.legend(loc='lower right')
plt.ylim([0.8, 1.05])
plt.show()
# Zdefiniowanie zakresu parametru do testowania (np. liczba składników)
param_range = [1, 2, 3, 4, 5] # Możesz dostosować zakres parametru do własnych potrzeb
# Wygenerowanie krzywej walidacji dla parametru w modelu LDA
train_scores, test_scores = validation_curve(estimator=lda,
X=X_train,
y=y_train,
param_name='n_components', # Parametr do testowania
param_range=param_range,
cv=10) # Liczba podziałów walidacji krzyżowej
# Obliczenie średnich dokładności dla danych treningowych i testowych
train_mean = np.mean(train_scores, axis=1)
train_std = np.std(train_scores, axis=1)
test_mean = np.mean(test_scores, axis=1)
test_std = np.std(test_scores, axis=1)
# Wykreślenie krzywej walidacji
plt.plot(param_range, train_mean,
color='blue', marker='o',
markersize=5, label='Training accuracy')
plt.fill_between(param_range, train_mean + train_std,
train_mean - train_std, alpha=0.15,
color='blue')
plt.plot(param_range, test_mean,
color='green', linestyle='--',
marker='s', markersize=5,
label='Validation accuracy')
plt.fill_between(param_range,
test_mean + test_std,
test_mean - test_std,
alpha=0.15, color='green')
plt.grid()
plt.legend(loc='lower right')
plt.xlabel('Number of components')
plt.ylabel('Accuracy')
plt.ylim([0.8, 1.05])
plt.title('Validation Curve for Linear Discriminant Analysis')
plt.show()
# Definicja siatki parametrów do przeszukania
param_grid = {
'lineardiscriminantanalysis__solver': ['svd', 'lsqr', 'eigen'], # Wybór algorytmu optymalizacyjnego
'lineardiscriminantanalysis__shrinkage': [None, 'auto', 0.1, 0.5, 0.9], # Parametr zwężenia (shrinkage)
'lineardiscriminantanalysis__n_components': [None, 1, 2, 3] # Możesz dostosować te parametry
}
# Utworzenie obiektu GridSearchCV
gs_lda = GridSearchCV(estimator=pipe_lda,
param_grid=param_grid,
scoring='accuracy', # Wybór metryki oceny
cv=5, # Liczba podziałów walidacji krzyżowej
n_jobs=-1) # Wykorzystanie wszystkich rdzeni procesora
# Uruchomienie procesu przeszukiwania siatki hiperparametrów
gs_lda.fit(X_train, y_train)
# Wyświetlenie najlepszych parametrów i wyników
print(gs_lda.best_score_)
print(gs_lda.best_params_)
clf_lda = gs_lda.best_estimator_
clf_lda.fit(X_train, y_train)
print(f'Test accuracy: {clf_lda.score(X_test, y_test):.3f}')
Test accuracy: 0.923
scorer = make_scorer(f1_score, pos_label = 0)
gs = GridSearchCV(estimator = pipe_lda,
param_grid = param_grid,
scoring = scorer,
cv = 2)
gs = gs.fit(X_train, y_train)
print(gs.best_score_)
print(gs.best_params_)
nested_gs_lda = GridSearchCV(estimator = pipe_lda,
param_grid = param_grid,
scoring = 'accuracy',
cv = 2)
nested_scores_lda = cross_val_score(nested_gs_lda, X_train, y_train,
scoring = 'accuracy', cv = 5)
print(f'CV accuracy: {np.mean(nested_scores_lda):.3f}'
f' +/- {np.std(nested_scores_lda):.3f}')
# Utworzenie potoku dla LDA
pipe_lda = Pipeline([
('scaler', StandardScaler()), # Jeśli potrzebna jest normalizacja danych
('lda', LDA())
])
# Definicja przestrzeni parametrów do przeszukania
param_dist = {
'lda__solver': ['svd', 'lsqr', 'eigen'], # Wybór algorytmu optymalizacyjnego
'lda__shrinkage': [None, 'auto'], # Parametr zwężenia (shrinkage)
'lda__n_components': [None, 1, 2, 3] # Liczba komponentów do uwzględnienia
}
# Inicjalizacja RandomizedSearchCV
rs_lda = RandomizedSearchCV(
estimator=pipe_lda,
param_distributions=param_dist,
scoring='accuracy',
cv=5,
n_iter=10,
n_jobs=-1,
random_state=42
)
# Dopasowanie modelu
rs_lda.fit(X_train, y_train)
# Wyświetlenie najlepszego wyniku i najlepszych parametrów
print(rs_lda.best_score_)
print(rs_lda.best_params_)
# Inicjalizacja klasyfikatora QDA
qda = QDA()
# Dopasowanie klasyfikatora do danych
qda.fit(X_train_pca, y_train)
# Wizualizacja granic decyzyjnych
plot_decision_regions(X_train_pca, y_train, classifier=qda)
plt.xlabel('PC 1')
plt.ylabel('PC 2')
plt.title('Decision Boundary for QDA')
plt.show()
plot_decision_regions(X_test_pca, y_test, classifier=qda)
plt.xlabel('PC 1')
plt.ylabel('PC 2')
plt.legend(loc='best')
plt.tight_layout()
plt.show()
pipe_qda = make_pipeline(StandardScaler(),
QDA())
pipe_qda.fit(X_train, y_train)
y_pred = pipe_qda.predict(X_test)
test_acc_qda = pipe_qda.score(X_test, y_test)
print(f'Test accuracy: {test_acc_qda: .3f}')
Test accuracy: 0.913
pipe_qda.fit(X_train, y_train)
y_pred = pipe_qda.predict(X_test)
confmat = confusion_matrix(y_true = y_test, y_pred = y_pred)
print(confmat)
[[303 23] [ 43 393]]
fig, ax = plt.subplots(figsize = (2.5, 2.5))
ax.matshow(confmat, cmap = plt.cm.Blues, alpha = 0.3)
for i in range(confmat.shape[0]):
for j in range(confmat.shape[1]):
ax.text(x = j, y = i, s = confmat[i, j],
va = 'center', ha = 'center')
ax.xaxis.set_ticks_position('bottom')
plt.xlabel('Predicted label')
plt.ylabel('True label')
plt.show()
scores_qda = cross_val_score(estimator = pipe_qda,
X = X_train,
y = y_train,
cv = 10,
n_jobs = 1)
print(f'CV accuracy scores: {scores_qda}')
print(f'CV accuracy scores: {np.mean(scores_qda):.3f}'
f' +/- {np.std(scores_qda):.3f}')
CV accuracy scores: [0.92459016 0.93114754 0.90819672 0.92786885 0.92786885 0.95081967 0.94098361 0.92459016 0.91447368 0.92763158] CV accuracy scores: 0.928 +/- 0.011
pre_val_qda = precision_score(y_true = y_test, y_pred = y_pred)
print(f'Precision: {pre_val_qda}')
rec_val_qda = recall_score(y_true = y_test, y_pred = y_pred)
print(f'Recall: {rec_val_qda}')
f1_val_qda = f1_score(y_true = y_test, y_pred = y_pred)
print(f'F1: {f1_val_qda}')
mcc_val_qda = matthews_corrcoef(y_true = y_test, y_pred = y_pred)
print(f'MCC: {mcc_val_qda:.3f}')
Precision: 0.9447115384615384 Recall: 0.9013761467889908 F1: 0.9225352112676056 MCC: 0.826
# Podział danych do walidacji krzyżowej
cv = list(StratifiedKFold(n_splits=3).split(X_train, y_train))
# Inicjalizacja wykresu
fig = plt.figure(figsize=(7, 5))
mean_fpr = np.linspace(0, 1, 100)
all_tpr = []
# Dla każdego podziału walidacji krzyżowej
for i, (train, test) in enumerate(cv):
# Dopasowanie modelu do danych treningowych
probas = pipe_qda.fit(X_train[train], y_train[train]).predict_proba(X_train[test])
# Obliczenie współczynników True Positive Rate (TPR) oraz False Positive Rate (FPR)
fpr, tpr, thresholds = roc_curve(y_train[test], probas[:, 1], pos_label=1)
# Interpolacja wyników na średnią krzywą ROC
mean_tpr = np.interp(mean_fpr, fpr, tpr)
mean_tpr[0] = 0.0
all_tpr.append(mean_tpr)
# Obliczenie pola pod krzywą ROC (AUC)
roc_auc = auc(fpr, tpr)
# Wyświetlenie krzywej ROC dla każdego podziału
plt.plot(fpr, tpr, label=f'ROC fold {i+1} (area = {roc_auc:.2f})')
# Obliczenie średniego True Positive Rate
mean_tpr = np.mean(all_tpr, axis=0)
mean_tpr[-1] = 1.0
# Obliczenie średniego pola pod krzywą ROC (AUC)
mean_auc = auc(mean_fpr, mean_tpr)
# Wyświetlenie średniej krzywej ROC
plt.plot(mean_fpr, mean_tpr, 'k--', label=f'Mean ROC (area = {mean_auc:.2f})', lw=2)
# Wyświetlenie linii referencyjnych
plt.plot([0, 1], [0, 1], linestyle='--', color=(0.6, 0.6, 0.6), label='Random guessing (area=0.5)')
plt.plot([0, 0, 1], [0, 1, 1], linestyle=':', color='black', label='Perfect performance (area=1.0)')
# Ustawienia osi i legendy
plt.xlim([-0.05, 1.05])
plt.ylim([-0.05, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.legend(loc='lower right')
plt.tight_layout()
plt.show()
# Wygenerowanie krzywej uczenia
train_sizes, train_scores, test_scores = learning_curve(estimator=pipe_qda,
X=X_train,
y=y_train,
train_sizes=np.linspace(0.1, 1.0, 10),
cv=10,
n_jobs=1)
# Obliczenie średnich i odchyleń standardowych dokładności dla danych treningowych i testowych
train_mean = np.mean(train_scores, axis=1)
train_std = np.std(train_scores, axis=1)
test_mean = np.mean(test_scores, axis=1)
test_std = np.std(test_scores, axis=1)
# Wykreślenie krzywej uczenia
plt.plot(train_sizes, train_mean,
color='blue', marker='o',
markersize=5, label='Training accuracy')
plt.fill_between(train_sizes,
train_mean + train_std,
train_mean - train_std,
alpha=0.15, color='blue')
plt.plot(train_sizes, test_mean,
color='green', linestyle='--',
marker='s', markersize=5,
label='Validation accuracy')
plt.fill_between(train_sizes,
test_mean + test_std,
test_mean - test_std,
alpha=0.15, color='green')
plt.grid()
plt.xlabel('Number of training examples')
plt.ylabel('Accuracy')
plt.legend(loc='lower right')
plt.ylim([0.8, 1.05])
plt.show()
# Zdefiniowanie zakresu parametru reg_param do testowania
param_range_reg_param = [0.0001, 0.001, 0.01, 0.1, 1.0]
# Wygenerowanie krzywej walidacji dla parametru reg_param w QDA
train_scores, test_scores = validation_curve(estimator=pipe_qda,
X=X_train,
y=y_train,
param_name='quadraticdiscriminantanalysis__reg_param',
param_range=param_range_reg_param,
cv=10)
# Obliczenie średnich dokładności dla danych treningowych i testowych
train_mean = np.mean(train_scores, axis=1)
train_std = np.std(train_scores, axis=1)
test_mean = np.mean(test_scores, axis=1)
test_std = np.std(test_scores, axis=1)
# Wykreślenie krzywej walidacji
plt.plot(param_range_reg_param, train_mean,
color='blue', marker='o',
markersize=5, label='Training accuracy')
plt.fill_between(param_range_reg_param, train_mean + train_std,
train_mean - train_std, alpha=0.15,
color='blue')
plt.plot(param_range_reg_param, test_mean,
color='green', linestyle='--',
marker='s', markersize=5,
label='Validation accuracy')
plt.fill_between(param_range_reg_param,
test_mean + test_std,
test_mean - test_std,
alpha=0.15, color='green')
plt.grid()
plt.xscale('log')
plt.legend(loc='lower right')
plt.xlabel('Parameter reg_param')
plt.ylabel('Accuracy')
plt.ylim([0.8, 1.05])
plt.title('Validation Curve for QDA')
plt.show()
# Utworzenie potoku zawierającego StandardScaler i QDA
pipe_qda = make_pipeline(StandardScaler(), QDA())
# Definicja siatki parametrów do przeszukania
param_grid = {
'quadraticdiscriminantanalysis__reg_param': [0.1, 0.5, 1.0] # Przykładowe wartości dla parametru reg_param
}
# Utworzenie obiektu GridSearchCV
gs_qda = GridSearchCV(estimator=pipe_qda,
param_grid=param_grid,
scoring='accuracy', # Wybór metryki oceny
cv=5, # Liczba podziałów walidacji krzyżowej
n_jobs=-1) # Wykorzystanie wszystkich rdzeni procesora
# Uruchomienie procesu przeszukiwania siatki hiperparametrów
gs_qda.fit(X_train, y_train)
# Wyświetlenie najlepszych parametrów i wyników
print(gs_qda.best_score_)
print(gs_qda.best_params_)
0.9288007752563999
{'quadraticdiscriminantanalysis__reg_param': 0.1}
clf_qda = gs_qda.best_estimator_
clf_qda.fit(X_train, y_train)
print(f'Test accuracy: {clf_qda.score(X_test, y_test):.3f}')
Test accuracy: 0.925
scorer = make_scorer(f1_score, pos_label = 0)
gs = GridSearchCV(estimator = pipe_qda,
param_grid = param_grid,
scoring = scorer,
cv = 2)
gs = gs.fit(X_train, y_train)
print(gs.best_score_)
print(gs.best_params_)
0.9157727180786042
{'quadraticdiscriminantanalysis__reg_param': 0.1}
nested_gs_qda = GridSearchCV(estimator = pipe_qda,
param_grid = param_grid,
scoring = 'accuracy',
cv = 2)
nested_scores_qda = cross_val_score(nested_gs_qda, X_train, y_train,
scoring = 'accuracy', cv = 5)
print(f'CV accuracy: {np.mean(nested_scores_qda):.3f}'
f' +/- {np.std(nested_scores_qda):.3f}')
CV accuracy: 0.929 +/- 0.010
# Utworzenie potoku dla QDA
pipe_qda = Pipeline([
('scaler', StandardScaler()), # Jeśli potrzebna jest normalizacja danych
('qda', QDA())
])
# Definicja przestrzeni parametrów do przeszukania
param_dist = {
'qda__reg_param': [0.1, 0.5, 1.0] # Parametr regularyzacji QDA
# Dodatkowe parametry QDA można również tutaj uwzględnić
}
# Inicjalizacja RandomizedSearchCV
rs_qda = RandomizedSearchCV(
estimator=pipe_qda,
param_distributions=param_dist,
scoring='accuracy',
cv=5,
n_iter=10,
n_jobs=-1,
random_state=42
)
# Dopasowanie modelu
rs_qda.fit(X_train, y_train)
# Wyświetlenie najlepszego wyniku i najlepszych parametrów
print(rs_qda.best_score_)
print(rs_qda.best_params_)
0.9288007752563999
{'qda__reg_param': 0.1}
c:\Users\Dawid\anaconda3\Lib\site-packages\sklearn\model_selection\_search.py:307: UserWarning: The total space of parameters 3 is smaller than n_iter=10. Running 3 iterations. For exhaustive searches, use GridSearchCV. warnings.warn(
klasyfikatory = [
"Regresja logistyczna",
"SVM",
"Drzewo decyzyjne",
"KNN",
"Lasy Losowe",
"Sieci neuronowe",
"LDA",
"QDA"
]
dokladnosci = [test_acc_lr, test_acc_svc, test_acc_dt, test_acc_knn, test_acc_forest, test_acc_mlp, test_acc_lda, test_acc_qda]
dokladnosci_CV = [np.mean(scores_lr), np.mean(scores_svc), np.mean(scores_dt), np.mean(scores_knn),
np.mean(scores_forest), np.mean(scores_mlp), np.mean(scores_lda), np.mean(scores_qda)]
dokladnosci_2 = [pre_val_lr, pre_val_svc, pre_val_dt, pre_val_knn, pre_val_forest, pre_val_mlp, pre_val_lda, pre_val_qda]
recall = [rec_val_lr, rec_val_svc, rec_val_dt, rec_val_knn, rec_val_forest, rec_val_mlp, rec_val_lda, rec_val_qda]
f1 = [f1_val_lr, f1_val_svc, f1_val_dt, f1_val_knn, f1_val_forest, f1_val_mlp, f1_val_lda, f1_val_qda]
mcc = [mcc_val_lr, mcc_val_svc, mcc_val_dt, mcc_val_knn, mcc_val_forest, mcc_val_mlp, mcc_val_lda, mcc_val_qda]
grid_search = [gs_lr.best_score_, gs_svc.best_score_, gs_dt.best_score_, gs_knn.best_score_,
gs_forest.best_score_, gs_mlp.best_score_, gs_lda.best_score_, gs_qda.best_score_]
nested_grid_seach = [np.mean(nested_scores_lr), np.mean(nested_scores_lr), np.mean(nested_scores_dt), np.mean(nested_scores_knn),
np.mean(nested_scores_forest), np.mean(nested_scores_mlp), np.mean(nested_scores_lda), np.mean(nested_scores_qda)]
random_search = [rs_lr.best_score_, rs_svc.best_score_, rs_dt.best_score_, rs_knn.best_score_,
rs_forest.best_score_, rs_mlp.best_score_, rs_lda.best_score_, rs_qda.best_score_]
# Convert 'klasyfikatory' to a DataFrame
classifier_df = pd.DataFrame({"Klasyfikator": klasyfikatory})
# Create the summary DataFrame
df = pd.DataFrame({
"Dokładność": dokladnosci,
"Dokładność CV": dokladnosci_CV,
"Zoptymalizowana dokładność": dokladnosci_2,
"Recall": recall,
"F1 score": f1,
"MCC": mcc,
"Grid Search": grid_search,
"Zagnieżdżony Grid Search": nested_grid_seach,
"Random Search": random_search
})
# Concatenate the 'classifier_df' and 'df' DataFrames along the columns axis
summary = pd.concat([classifier_df, df], axis=1)
summary
| Klasyfikator | Dokładność | Dokładność CV | Zoptymalizowana dokładność | Recall | F1 score | MCC | Grid Search | Zagnieżdżony Grid Search | Random Search | |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | Regresja logistyczna | 0.922572 | 0.923227 | 0.939394 | 0.924312 | 0.931792 | 0.842423 | 0.931428 | 0.929783 | 0.931428 |
| 1 | SVM | 0.919948 | 0.931424 | 0.933025 | 0.926606 | 0.929804 | 0.836704 | 0.931424 | 0.929783 | 0.931424 |
| 2 | Drzewo decyzyjne | 0.888451 | 0.888764 | 0.911007 | 0.892202 | 0.901506 | 0.773169 | 0.924537 | 0.924537 | 0.925523 |
| 3 | KNN | 0.918635 | 0.920273 | 0.932870 | 0.924312 | 0.928571 | 0.834112 | 0.925849 | 0.923880 | 0.925849 |
| 4 | Lasy Losowe | 0.925197 | 0.920925 | 0.935632 | 0.933486 | 0.934558 | 0.847272 | 0.927160 | 0.923550 | 0.928472 |
| 5 | Sieci neuronowe | 0.925197 | 0.928142 | 0.939675 | 0.928899 | 0.934256 | 0.847581 | 0.929458 | 0.928143 | 0.691569 |
| 6 | LDA | 0.922572 | 0.931755 | 0.921700 | 0.944954 | 0.933182 | 0.841542 | 0.931097 | 0.931097 | 0.931097 |
| 7 | QDA | 0.913386 | 0.927817 | 0.944712 | 0.901376 | 0.922535 | 0.825613 | 0.928801 | 0.928801 | 0.928801 |
best_estimator_gs = [gs_lr.best_params_, gs_svc.best_params_, gs_dt.best_params_, gs_knn.best_params_,
gs_forest.best_params_, gs_mlp.best_params_, gs_lda.best_params_, gs_qda.best_params_]
best_estimator_rs = [rs_lr.best_params_, rs_svc.best_params_, rs_dt.best_params_, rs_knn.best_params_,
rs_forest.best_params_, rs_mlp.best_params_, rs_lda.best_params_, rs_qda.best_params_]
lista = []
parametry = []
for klasyfikator, estim in zip(klasyfikatory, best_estimator_gs):
for key in estim:
lista.append(klasyfikator)
parametry.append(key)
index = [np.array(lista), np.array(parametry)]
results_01 = pd.DataFrame(np.zeros((len(index[0]), 1)), index=index, columns=["Grid Search CV"])
for klasyfikator, dict in zip(klasyfikatory, best_estimator_gs):
for param, value in dict.items():
results_01.loc[(klasyfikator, param), "Grid Search CV"] = value
results_01
| Grid Search CV | ||
|---|---|---|
| Regresja logistyczna | logisticregression__C | 10.0 |
| logisticregression__solver | sag | |
| SVM | svc__C | 10.0 |
| svc__kernel | linear | |
| Drzewo decyzyjne | decisiontreeclassifier__criterion | gini |
| decisiontreeclassifier__max_depth | 1 | |
| decisiontreeclassifier__min_samples_leaf | 1 | |
| decisiontreeclassifier__min_samples_split | 2 | |
| KNN | kneighborsclassifier__metric | euclidean |
| kneighborsclassifier__n_neighbors | 11 | |
| Lasy Losowe | randomforestclassifier__bootstrap | False |
| randomforestclassifier__max_depth | 5 | |
| randomforestclassifier__n_estimators | 50 | |
| Sieci neuronowe | mlpclassifier__activation | logistic |
| mlpclassifier__alpha | 0.01 | |
| mlpclassifier__hidden_layer_sizes | (100, 100) | |
| LDA | lineardiscriminantanalysis__n_components | None |
| lineardiscriminantanalysis__shrinkage | None | |
| lineardiscriminantanalysis__solver | svd | |
| QDA | quadraticdiscriminantanalysis__reg_param | 0.1 |
lista = []
parametry = []
for klasyfikator, estim in zip(klasyfikatory, best_estimator_rs):
for key in estim:
lista.append(klasyfikator)
parametry.append(key)
index = [np.array(lista), np.array(parametry)]
results_02 = pd.DataFrame(np.zeros((len(index[0]), 1)), index=index, columns=["Randomized Search CV"])
for klasyfikator, dict in zip(klasyfikatory, best_estimator_rs):
for param, value in dict.items():
results_02.loc[(klasyfikator, param), "Randomized Search CV"] = value
results_02
| Randomized Search CV | ||
|---|---|---|
| Regresja logistyczna | logisticregression__solver | sag |
| logisticregression__C | 10.0 | |
| SVM | svc__kernel | linear |
| svc__C | 10.0 | |
| Drzewo decyzyjne | decisiontreeclassifier__criterion | entropy |
| decisiontreeclassifier__max_depth | 4 | |
| decisiontreeclassifier__min_samples_leaf | 14 | |
| decisiontreeclassifier__min_samples_split | 32 | |
| KNN | kneighborsclassifier__metric | minkowski |
| kneighborsclassifier__n_neighbors | 11 | |
| Lasy Losowe | randomforestclassifier__bootstrap | True |
| randomforestclassifier__max_depth | 30 | |
| randomforestclassifier__min_samples_leaf | 15 | |
| randomforestclassifier__min_samples_split | 12 | |
| randomforestclassifier__n_estimators | 171 | |
| Sieci neuronowe | hidden_layer_sizes | (100,) |
| alpha | 0.001 | |
| activation | relu | |
| LDA | lda__solver | eigen |
| lda__shrinkage | None | |
| lda__n_components | 1 | |
| QDA | qda__reg_param | 0.1 |
Widzimy, że wszystkie wyniki dają bardzo wysokie rezultaty, co pokazuje nam, że klasyfikacja została zrealizowana pomyślnie. Najwyższe wyniki dały takie klasyfikatory jak: LDA, regresja logistyczna, lasy losowe, czy sieci neuronowe. Obserwacje zaklasyfikowane $Cammeo$ i $Osmancik$ w bardzo dużym procencie przypadków zostało poprawnie zaklasyfikowane.